You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ac...@apache.org on 2018/09/18 15:14:51 UTC
qpid-proton git commit: PROTON-1935: [cpp] connection configuration
and default connect()
Repository: qpid-proton
Updated Branches:
refs/heads/master 348e9da89 -> b164d99c8
PROTON-1935: [cpp] connection configuration and default connect()
docs/connect-config.md: describes connection configuration JSON format.
container::connect() connects using the default configuration file
Additional API in proton::connect_config allows the user to parse configuration
and apply to a connection_options object for more flexible use.
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/b164d99c
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/b164d99c
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/b164d99c
Branch: refs/heads/master
Commit: b164d99c80129a2a24ae7203846579569c9cf3b5
Parents: 348e9da
Author: Alan Conway <ac...@redhat.com>
Authored: Tue Sep 18 09:31:47 2018 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Tue Sep 18 11:03:25 2018 -0400
----------------------------------------------------------------------
INSTALL.md | 2 +
c/include/proton/cproton.i | 1 +
c/include/proton/version.h.in | 2 +
cpp/CMakeLists.txt | 20 ++-
cpp/docs/CMakeLists.txt | 2 +-
cpp/docs/user.doxygen.in | 3 +-
cpp/include/proton/connect_config.hpp | 49 +++++++
cpp/include/proton/container.hpp | 6 +
cpp/src/connect_config.cpp | 219 +++++++++++++++++++++++++++++
cpp/src/connect_config_dummy.cpp | 31 ++++
cpp/src/connect_config_test.cpp | 142 +++++++++++++++++++
cpp/src/connection_options.cpp | 1 +
cpp/src/container.cpp | 4 +
cpp/src/proactor_container_impl.cpp | 7 +
cpp/src/proactor_container_impl.hpp | 1 +
cpp/src/test_bits.hpp | 8 ++
docs/connect_config.md | 42 ++++++
tools/cmake/Modules/FindJsonCpp.cmake | 70 +++++++++
18 files changed, 607 insertions(+), 3 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b164d99c/INSTALL.md
----------------------------------------------------------------------
diff --git a/INSTALL.md b/INSTALL.md
index 430d648..76e6af2 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -20,6 +20,7 @@ Linux dependencies
- GCC 4.4+
- Cyrus SASL 2.1+ (for SASL support)
- OpenSSL 1.0+ (for SSL support)
+ - JsonCpp 1.8+ for C++ connection configuration file support
Windows dependencies
@@ -46,6 +47,7 @@ language.
$ yum install swig # Required for all bindings
$ yum install python-devel # Python
$ yum install ruby-devel rubygem-minitest # Ruby
+ $ yum install jsoncpp-devel # C++ optional config file
# Dependencies needed to generate documentation
$ yum install epydoc # Python
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b164d99c/c/include/proton/cproton.i
----------------------------------------------------------------------
diff --git a/c/include/proton/cproton.i b/c/include/proton/cproton.i
index 430deca..c642438 100644
--- a/c/include/proton/cproton.i
+++ b/c/include/proton/cproton.i
@@ -37,6 +37,7 @@ typedef unsigned long int uintptr_t;
%include "proton/import_export.h"
%ignore _PROTON_VERSION_H;
+%ignore PN_INSTALL_PREFIX;
%include "proton/version.h"
/* We cannot safely just wrap pn_bytes_t but each language binding must have a typemap for it - presumably to a string type */
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b164d99c/c/include/proton/version.h.in
----------------------------------------------------------------------
diff --git a/c/include/proton/version.h.in b/c/include/proton/version.h.in
index 133b0bb..13ee411 100644
--- a/c/include/proton/version.h.in
+++ b/c/include/proton/version.h.in
@@ -26,4 +26,6 @@
#define PN_VERSION_MINOR @PN_VERSION_MINOR@
#define PN_VERSION_POINT @PN_VERSION_POINT@
+#define PN_INSTALL_PREFIX "@CMAKE_INSTALL_PREFIX@"
+
#endif /* version.h */
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b164d99c/cpp/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt
index d0b3cfb..35f5478 100644
--- a/cpp/CMakeLists.txt
+++ b/cpp/CMakeLists.txt
@@ -27,6 +27,16 @@ include(versions.cmake)
set (BUILD_CPP_03 OFF CACHE BOOL "Compile the C++ binding as C++03 even when C++11 is available")
+# Check for JSON-CPP support for connection configuration
+find_package(JsonCpp)
+option(ENABLE_JSONCPP "Use jsoncpp parser for connection configuration" ${JsonCpp_FOUND})
+if (ENABLE_JSONCPP)
+ set(CONNECT_CONFIG_SRC src/connect_config.cpp)
+ set(CONNECT_CONFIG_LIBS ${JsonCpp_LIBRARY})
+else()
+ set(CONNECT_CONFIG_SRC src/connect_config_dummy.cpp)
+endif()
+
# This effectively checks for cmake version 3.1 or later
if (DEFINED CMAKE_CXX_COMPILE_FEATURES)
if (BUILD_CPP_03)
@@ -150,6 +160,7 @@ set(qpid-proton-cpp-source
src/uuid.cpp
src/value.cpp
src/work_queue.cpp
+ ${CONNECT_CONFIG_SRC}
)
set_source_files_properties (
@@ -167,7 +178,7 @@ if(BUILD_STATIC_LIBS)
add_library(qpid-proton-cpp-static STATIC ${qpid-proton-cpp-source})
endif(BUILD_STATIC_LIBS)
-target_link_libraries (qpid-proton-cpp LINK_PRIVATE ${PLATFORM_LIBS} qpid-proton-core qpid-proton-proactor)
+target_link_libraries (qpid-proton-cpp LINK_PRIVATE ${PLATFORM_LIBS} qpid-proton-core qpid-proton-proactor ${CONNECT_CONFIG_LIBS})
set_target_properties (
qpid-proton-cpp
@@ -258,3 +269,10 @@ add_cpp_test(container_test)
add_cpp_test(url_test)
add_cpp_test(reconnect_test)
add_cpp_test(link_test)
+if (ENABLE_JSONCPP)
+ # Directories needed by connect_config tests
+ file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/testdata/.config/messaging")
+ add_cpp_test(connect_config_test)
+ set_tests_properties(cpp-connect_config_test PROPERTIES
+ WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
+endif()
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b164d99c/cpp/docs/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/cpp/docs/CMakeLists.txt b/cpp/docs/CMakeLists.txt
index d512d15..690230d 100644
--- a/cpp/docs/CMakeLists.txt
+++ b/cpp/docs/CMakeLists.txt
@@ -24,7 +24,7 @@ if (DOXYGEN_FOUND)
${CMAKE_CURRENT_SOURCE_DIR}/user.doxygen.in
${CMAKE_CURRENT_BINARY_DIR}/user.doxygen)
- file(GLOB_RECURSE headers ../include/proton/*.hpp)
+ file(GLOB_RECURSE sources ../include/proton/*.hpp ../../connect_config.md)
add_custom_target (docs-cpp
COMMAND ${CMAKE_COMMAND} -E remove_directory html # get rid of old files
COMMAND ${DOXYGEN_EXECUTABLE} user.doxygen
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b164d99c/cpp/docs/user.doxygen.in
----------------------------------------------------------------------
diff --git a/cpp/docs/user.doxygen.in b/cpp/docs/user.doxygen.in
index 6bcd1bd..84375d8 100644
--- a/cpp/docs/user.doxygen.in
+++ b/cpp/docs/user.doxygen.in
@@ -55,7 +55,8 @@ WARNINGS = YES
INPUT = @CMAKE_SOURCE_DIR@/cpp/include \
@CMAKE_SOURCE_DIR@/cpp/docs \
- @CMAKE_SOURCE_DIR@/cpp/examples
+ @CMAKE_SOURCE_DIR@/cpp/examples \
+ @CMAKE_SOURCE_DIR@/docs/connect_config.md
FILE_PATTERNS = *.hpp *.md *.dox
EXCLUDE_PATTERNS = @CMAKE_SOURCE_DIR@/cpp/examples/*.?pp \
@CMAKE_SOURCE_DIR@/cpp/include/proton/internal/*.hpp
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b164d99c/cpp/include/proton/connect_config.hpp
----------------------------------------------------------------------
diff --git a/cpp/include/proton/connect_config.hpp b/cpp/include/proton/connect_config.hpp
new file mode 100644
index 0000000..be5c7ac
--- /dev/null
+++ b/cpp/include/proton/connect_config.hpp
@@ -0,0 +1,49 @@
+#ifndef CONNECT_CONFIG_HPP
+#define CONNECT_CONFIG_HPP
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <proton/connection_options.hpp>
+
+namespace proton {
+
+class connection_options;
+
+/// *Unsettled API*
+namespace connect_config {
+
+/// @return name of the default connection configuration file
+/// @throw proton::error if no default file is found
+PN_CPP_EXTERN std::string default_file();
+
+/// Parse configuration from @p is and update @p opts
+/// @param is input stream for configuration file/string
+/// @param opts [out] connection options to update
+/// @return address suitable for container::connect() from configuration
+PN_CPP_EXTERN std::string parse(std::istream& is, connection_options& opts);
+
+/// Parse configuration from default_file() and update @p opts
+/// @param opts [out] connection options to update
+/// @return address suitable for container::connect() from configuration
+PN_CPP_EXTERN std::string parse_default(connection_options& opts);
+
+}} // namespace proton::connect_config
+
+#endif // CONNECT_CONFIG_HPP
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b164d99c/cpp/include/proton/container.hpp
----------------------------------------------------------------------
diff --git a/cpp/include/proton/container.hpp b/cpp/include/proton/container.hpp
index 27ac498..362dba0 100644
--- a/cpp/include/proton/container.hpp
+++ b/cpp/include/proton/container.hpp
@@ -113,6 +113,12 @@ class PN_CPP_CLASS_EXTERN container {
/// @copydetails returned
PN_CPP_EXTERN returned<connection> connect(const std::string& conn_url);
+ /// Connect using the default @ref connect_config
+ /// FIXME aconway 2018-08-07: cmake - copy connect_config.md into C++ doc
+ ///
+ /// @copydetails returned
+ PN_CPP_EXTERN returned<connection> connect();
+
/// Listen for new connections on `listen_url`.
///
/// If the listener opens successfully, listen_handler::on_open() is called.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b164d99c/cpp/src/connect_config.cpp
----------------------------------------------------------------------
diff --git a/cpp/src/connect_config.cpp b/cpp/src/connect_config.cpp
new file mode 100644
index 0000000..0dc577a
--- /dev/null
+++ b/cpp/src/connect_config.cpp
@@ -0,0 +1,219 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "msg.hpp"
+
+#include <proton/connect_config.hpp>
+#include <proton/error.hpp>
+#include <proton/ssl.hpp>
+
+#include <proton/version.h>
+
+#include <json/value.h>
+#include <json/reader.h>
+
+#include <cstdlib>
+#include <fstream>
+
+using namespace Json;
+using std::string;
+
+namespace {
+const char *type_name(ValueType t) {
+ switch (t) {
+ case nullValue: return "null";
+ case intValue: return "int";
+ case uintValue: return "uint";
+ case realValue: return "real";
+ case stringValue: return "string";
+ case booleanValue: return "boolean";
+ case arrayValue: return "array";
+ case objectValue: return "object";
+ default: return "unknown";
+ }
+}
+} // namespace
+
+namespace std {
+ostream& operator<<(ostream& o, ValueType t) { return o << type_name(t); }
+}
+
+namespace proton {
+namespace connect_config {
+
+namespace {
+
+void raise(const string& message) {
+ throw proton::error("connection configuration: " + message);
+}
+
+Value validate(ValueType t, const Value& v, const string& name) {
+ if (v.type() != t)
+ raise(msg() << " '" << name << "' expected " << t << ", found " << v.type());
+ return v;
+}
+
+Value get(ValueType t, const Value& obj, const char *key, const Value& dflt=Value()) {
+ Value v = obj ? obj.get(key, dflt) : dflt;
+ return validate(t, v, key);
+}
+
+bool get_bool(const Value& obj, const char *key, bool dflt) {
+ return get(booleanValue, obj, key, dflt).asBool();
+}
+
+string get_string(const Value& obj, const char *key, const string& dflt) {
+ return get(stringValue, obj, key, dflt).asString();
+}
+
+static const string HOME("HOME");
+static const string ENV_VAR("MESSAGING_CONNECT_FILE");
+static const string FILE_NAME("connect.json");
+static const string HOME_FILE_NAME("/.config/messaging/" + FILE_NAME);
+static const string ETC_FILE_NAME("/etc/messaging/" + FILE_NAME);
+
+bool exists(const string& name) { return std::ifstream(name.c_str()).good(); }
+
+void parse_sasl(Value root, connection_options& opts) {
+ Value sasl = root.get("sasl", Value());
+ opts.sasl_enabled(get_bool(sasl, "enable", true));
+ if (sasl) {
+ validate(objectValue, sasl, "sasl");
+ opts.sasl_allow_insecure_mechs(get_bool(sasl, "allow_insecure", false));
+ Value mechs = sasl.get("mechanisms", Value());
+ switch (mechs.type()) {
+ case nullValue:
+ break;
+ case stringValue:
+ opts.sasl_allowed_mechs(mechs.asString());
+ break;
+ case arrayValue: {
+ std::ostringstream s;
+ for (ArrayIndex i= 0; i < mechs.size(); ++i) {
+ Value v = mechs.get(i, Value());
+ if (v.type() != stringValue) {
+ raise(msg() << "'sasl/mechanisms' expect string elements, found " << v.type());
+ }
+ if (i > 0) s << " ";
+ s << v.asString();
+ }
+ opts.sasl_allowed_mechs(s.str().c_str());
+ break;
+ }
+ default:
+ raise(msg() << "'mechanisms' expected string or array, found " << mechs.type());
+ }
+ }
+}
+
+void parse_tls(const string& scheme, Value root, connection_options& opts) {
+ Value tls = root.get("tls", Value());
+ if (tls) {
+ validate(objectValue, tls, "tls");
+ if (scheme != "amqps") {
+ raise(msg() << "'tls' object is not allowed unless scheme is \"amqps\"");
+ }
+ string ca = get_string(tls, "ca", "");
+ bool verify = get_bool(tls, "verify", true);
+ Value cert = get(stringValue, tls, "cert");
+ ssl::verify_mode mode = verify ? ssl::VERIFY_PEER_NAME : ssl::ANONYMOUS_PEER;
+ if (cert) {
+ Value key = get(stringValue, tls, "key");
+ ssl_certificate cert2 = key ?
+ ssl_certificate(cert.asString(), key.asString()) :
+ ssl_certificate(cert.asString());
+ opts.ssl_client_options(ssl_client_options(cert2, ca, mode));
+ } else {
+ ssl_client_options(ssl_client_options(ca, mode));
+ }
+ }
+}
+
+} // namespace
+
+std::string parse(std::istream& is, connection_options& opts) {
+ Value root;
+ is >> root;
+
+ string scheme = get_string(root, "scheme", "amqps");
+ if (scheme != "amqp" && scheme != "amqps") {
+ raise(msg() << "'scheme' must be \"amqp\" or \"amqps\"");
+ }
+
+ string host = get_string(root, "host", "");
+ opts.virtual_host(host.c_str());
+
+ Value port = root.get("port", scheme);
+ if (!port.isIntegral() && !port.isString()) {
+ raise(msg() << "'port' expected string or integer, found " << port.type());
+ }
+
+ Value user = root.get("user", Value());
+ if (user) opts.user(validate(stringValue, user, "user").asString());
+ Value password = root.get("password", Value());
+ if (password) opts.password(validate(stringValue, password, "password").asString());
+
+ parse_sasl(root, opts);
+ parse_tls(scheme, root, opts);
+ return host + ":" + port.asString();
+}
+
+string default_file() {
+ /* Use environment variable if set */
+ const char *env_path = getenv(ENV_VAR.c_str());
+ if (env_path) return env_path;
+ /* current directory */
+ if (exists(FILE_NAME)) return FILE_NAME;
+ /* $HOME/.config/messaging/FILE_NAME */
+ const char *home = getenv(HOME.c_str());
+ if (home) {
+ string path = home + HOME_FILE_NAME;
+ if (exists(path)) return path;
+ }
+ /* INSTALL_PREFIX/etc/messaging/FILE_NAME */
+ if (PN_INSTALL_PREFIX && *PN_INSTALL_PREFIX) {
+ string path = PN_INSTALL_PREFIX + ETC_FILE_NAME;
+ if (exists(path)) return path;
+ }
+ /* /etc/messaging/FILE_NAME */
+ if (exists(ETC_FILE_NAME)) return ETC_FILE_NAME;
+ raise("no default configuration");
+ return ""; // Never get here, keep compiler happy
+}
+
+string parse_default(connection_options& opts) {
+ string name = default_file();
+ std::ifstream f;
+ try {
+ f.exceptions(~std::ifstream::goodbit);
+ f.open(name);
+ } catch (const std::exception& e) {
+ raise(msg() << "error opening '" << name << "': " << e.what());
+ }
+ try {
+ return parse(f, opts);
+ } catch (const std::exception& e) {
+ raise(msg() << "error parsing '" << name << "': " << e.what());
+ } catch (...) {
+ raise(msg() << "error parsing '" << name);
+ }
+ return ""; // Never get here, keep compiler happy
+}
+
+}} // namespace proton::connect_config
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b164d99c/cpp/src/connect_config_dummy.cpp
----------------------------------------------------------------------
diff --git a/cpp/src/connect_config_dummy.cpp b/cpp/src/connect_config_dummy.cpp
new file mode 100644
index 0000000..4d46726
--- /dev/null
+++ b/cpp/src/connect_config_dummy.cpp
@@ -0,0 +1,31 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <proton/connect_config.hpp>
+#include <proton/error.hpp>
+
+namespace proton {
+namespace connect_config {
+namespace { const error nope("connection configuration is not supported"); }
+
+std::string default_file() { throw nope; }
+std::string parse(std::istream& is, connection_options& opts) { throw nope; }
+std::string parse_default(proton::connection_options&) { throw nope; }
+
+}} // namespace proton::connect_config
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b164d99c/cpp/src/connect_config_test.cpp
----------------------------------------------------------------------
diff --git a/cpp/src/connect_config_test.cpp b/cpp/src/connect_config_test.cpp
new file mode 100644
index 0000000..17f0c4b
--- /dev/null
+++ b/cpp/src/connect_config_test.cpp
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "test_bits.hpp"
+
+#include "proton/connect_config.hpp"
+#include "proton/connection.hpp"
+#include "proton/connection_options.hpp"
+#include "proton/container.hpp"
+#include "proton/error_condition.hpp"
+#include "proton/listener.hpp"
+#include "proton/messaging_handler.hpp"
+#include "proton/transport.hpp"
+
+#include <sstream>
+#include <fstream>
+#include <cstdio>
+
+#include <stdlib.h>
+
+namespace {
+
+using namespace std;
+using namespace proton;
+using proton::error_condition;
+
+string configure(connection_options& opts, const string& config) {
+ istringstream is(config);
+ return connect_config::parse(is, opts);
+}
+
+void test_default_file() {
+ // Default file locations in order of preference.
+ ::setenv("MESSAGING_CONNECT_FILE", "environment", 1);
+ ofstream("connect.json") << "{ \"host\": \"current\" }" << endl;
+ ::setenv("HOME", "testdata", 1);
+ ofstream("testdata/.config/messaging/connect.json") << "{ \"host\": \".config\" }" << endl;
+ ASSERT_EQUAL("environment", connect_config::default_file());
+ ::unsetenv("MESSAGING_CONNECT_FILE");
+ ASSERT_EQUAL("connect.json", connect_config::default_file());
+ remove("connect.json");
+ ASSERT_EQUAL("testdata/.config/messaging/connect.json", connect_config::default_file());
+ remove("testdata/.config/messaging/connect.json");
+
+ // We can't fully test prefix and /etc locations, we have no control.
+ try {
+ ASSERT_SUBSTRING("/etc/messaging", connect_config::default_file());
+ } catch (...) {} // OK if not there
+}
+
+void test_addr() {
+ connection_options opts;
+ ASSERT_EQUAL("foo:bar", configure(opts, "{ \"host\":\"foo\", \"port\":\"bar\" }"));
+ ASSERT_EQUAL("foo:1234", configure(opts, "{ \"host\":\"foo\", \"port\":\"1234\" }"));
+ ASSERT_EQUAL(":amqps", configure(opts, "{}"));
+ ASSERT_EQUAL(":amqp", configure(opts, "{\"scheme\":\"amqp\"}"));
+ ASSERT_EQUAL("foo:bar", configure(opts, "{ \"host\":\"foo\", /* inline comment */\"port\":\"bar\" // end of line comment\n}"));
+
+ ASSERT_THROWS_MSG(error, "'scheme' must be", configure(opts, "{\"scheme\":\"bad\"}"));
+ ASSERT_THROWS_MSG(error, "'scheme' expected string, found boolean", configure(opts, "{\"scheme\":true}"));
+ ASSERT_THROWS_MSG(error, "'port' expected string or integer, found boolean", configure(opts, "{\"port\":true}"));
+ ASSERT_THROWS_MSG(error, "'host' expected string, found boolean", configure(opts, "{\"host\":true}"));
+}
+
+class test_handler : public messaging_handler {
+ protected:
+ string config_;
+ listener listener_;
+ bool opened_;
+ proton::error_condition error_;
+
+ public:
+
+ void on_container_start(container& c) PN_CPP_OVERRIDE {
+ listener_ = c.listen("//:0");
+ }
+
+ virtual void check_connection(connection& c) {}
+
+ void on_connection_open(connection& c) PN_CPP_OVERRIDE {
+ if (!c.active()) { // Server side
+ opened_ = true;
+ check_connection(c);
+ listener_.stop();
+ c.close();
+ }
+ }
+
+ void on_error(const error_condition& e) PN_CPP_OVERRIDE {
+ FAIL("unexpected error " << e);
+ }
+
+ void run(const string& config) {
+ config_ = config;
+ container(*this).run();
+ }
+};
+
+class test_default_connect : public test_handler {
+ public:
+
+ void on_container_start(container& c) PN_CPP_OVERRIDE {
+ test_handler::on_container_start(c);
+ ofstream os("connect.json");
+ ASSERT(os << "{ \"port\": " << listener_.port() << "}" << endl);
+ os.close();
+ c.connect();
+ }
+
+ void run() {
+ container(*this).run();
+ ASSERT(opened_);
+ ASSERT(!error_);
+ }
+};
+
+} // namespace
+
+
+int main(int argc, char** argv) {
+ int failed = 0;
+ RUN_ARGV_TEST(failed, test_default_file());
+ RUN_ARGV_TEST(failed, test_addr());
+ RUN_ARGV_TEST(failed, test_default_connect().run());
+ return failed;
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b164d99c/cpp/src/connection_options.cpp
----------------------------------------------------------------------
diff --git a/cpp/src/connection_options.cpp b/cpp/src/connection_options.cpp
index 1903536..fdc770e 100644
--- a/cpp/src/connection_options.cpp
+++ b/cpp/src/connection_options.cpp
@@ -217,4 +217,5 @@ void connection_options::apply_unbound_client(pn_transport_t *t) const { impl_->
void connection_options::apply_unbound_server(pn_transport_t *t) const { impl_->apply_sasl(t); impl_->apply_ssl(t, false); impl_->apply_transport(t); }
messaging_handler* connection_options::handler() const { return impl_->handler.value; }
+
} // namespace proton
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b164d99c/cpp/src/container.cpp
----------------------------------------------------------------------
diff --git a/cpp/src/container.cpp b/cpp/src/container.cpp
index cfc0196..013fb4b 100644
--- a/cpp/src/container.cpp
+++ b/cpp/src/container.cpp
@@ -83,6 +83,10 @@ returned<connection> container::connect(const std::string& url, const connection
return impl_->connect(url, opts);
}
+returned<connection> container::connect() {
+ return impl_->connect();
+}
+
listener container::listen(const std::string& url, listen_handler& l) { return impl_->listen(url, l); }
void container::run() { impl_->run(1); }
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b164d99c/cpp/src/proactor_container_impl.cpp
----------------------------------------------------------------------
diff --git a/cpp/src/proactor_container_impl.cpp b/cpp/src/proactor_container_impl.cpp
index 01aea77..e0057cd 100644
--- a/cpp/src/proactor_container_impl.cpp
+++ b/cpp/src/proactor_container_impl.cpp
@@ -20,6 +20,7 @@
#include "proactor_container_impl.hpp"
#include "proactor_work_queue_impl.hpp"
+#include "proton/connect_config.hpp"
#include "proton/error_condition.hpp"
#include "proton/listener.hpp"
#include "proton/listen_handler.hpp"
@@ -350,6 +351,12 @@ returned<connection> container::impl::connect(
return make_returned<proton::connection>(pnc);
}
+returned<connection> container::impl::connect() {
+ connection_options opts;
+ std::string addr = connect_config::parse_default(opts);
+ return connect(addr, opts);
+}
+
returned<sender> container::impl::open_sender(const std::string &urlstr, const proton::sender_options &o1, const connection_options &o2)
{
proton::url url(urlstr);
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b164d99c/cpp/src/proactor_container_impl.hpp
----------------------------------------------------------------------
diff --git a/cpp/src/proactor_container_impl.hpp b/cpp/src/proactor_container_impl.hpp
index dcc9381..912a036 100644
--- a/cpp/src/proactor_container_impl.hpp
+++ b/cpp/src/proactor_container_impl.hpp
@@ -71,6 +71,7 @@ class container::impl {
impl(container& c, const std::string& id, messaging_handler* = 0);
~impl();
std::string id() const { return id_; }
+ returned<connection> connect();
returned<connection> connect(const std::string&, const connection_options&);
returned<sender> open_sender(
const std::string&, const proton::sender_options &, const connection_options &);
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b164d99c/cpp/src/test_bits.hpp
----------------------------------------------------------------------
diff --git a/cpp/src/test_bits.hpp b/cpp/src/test_bits.hpp
index 28271f0..50ea2ee 100644
--- a/cpp/src/test_bits.hpp
+++ b/cpp/src/test_bits.hpp
@@ -52,6 +52,11 @@ inline void assert_equalish(T want, T got, T delta, const std::string& what)
throw fail(MSG(what << " " << want << " !=~ " << got));
}
+void assert_substring(const std::string& want, const std::string& got, const std::string& what) {
+ if (got.find(want) == std::string::npos)
+ throw fail(MSG(what << " '" << want << "' not found in '" << got << "'"));
+}
+
#define FAIL_MSG(WHAT) (MSG(__FILE__ << ":" << __LINE__ << ": " << WHAT).str())
#define FAIL(WHAT) throw test::fail(FAIL_MSG(WHAT))
#define ASSERT(TEST) do { if (!(TEST)) FAIL("failed ASSERT(" #TEST ")"); } while(false)
@@ -59,7 +64,10 @@ inline void assert_equalish(T want, T got, T delta, const std::string& what)
test::assert_equal((WANT), (GOT), FAIL_MSG("failed ASSERT_EQUAL(" #WANT ", " #GOT ")"))
#define ASSERT_EQUALISH(WANT, GOT, DELTA) \
test::assert_equalish((WANT), (GOT), (DELTA), FAIL_MSG("failed ASSERT_EQUALISH(" #WANT ", " #GOT ")"))
+#define ASSERT_SUBSTRING(WANT, GOT) \
+ test::assert_substring((WANT), (GOT), FAIL_MSG("failed ASSERT_SUBSTRING(" #WANT ", " #GOT ")"))
#define ASSERT_THROWS(WANT, EXPR) do { try { EXPR; FAIL("Expected " #WANT); } catch(const WANT&) {} } while(0)
+#define ASSERT_THROWS_MSG(CLASS, MSG, EXPR) do { try { EXPR; FAIL("Expected " #CLASS); } catch(const CLASS& e) { ASSERT_SUBSTRING((MSG), e.what()); } } while(0)
#define RUN_TEST(BAD_COUNT, TEST) \
do { \
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b164d99c/docs/connect_config.md
----------------------------------------------------------------------
diff --git a/docs/connect_config.md b/docs/connect_config.md
new file mode 100644
index 0000000..f0419cc
--- /dev/null
+++ b/docs/connect_config.md
@@ -0,0 +1,42 @@
+# Connection Configuration
+
+Proton clients can read default connection information from a
+configuration file.
+
+If the environment variable `MESSAGING_CONNECT_FILE` is set, it is the
+path to the file. Otherwise the client looks for a file named
+`connect.json` in the following locations, using the first one found:
+
+* Current working directory of client process.
+* `$HOME/.config/messaging/` - $HOME is user's home directory.
+* `$PREFIX/etc/messaging/` - $PREFIX is the prefix where the proton library is installed
+* `/etc/messaging/`
+
+The configuration file is in JSON object format. Comments are allowed,
+as defined by the [JavaScript Minifier](https://www.crockford.com/javascript/jsmin.html)
+
+The file format is as follows. Properties are shown with their default
+values, all properties are optional.
+
+ {
+ "scheme": "amqps", // [string] "amqp" (no TLS) or "amqps"
+ "host": "", // [string] DNS or IP address for connection. Defaults to local host.
+ "port": "amqps", // [string] "amqp", "amqps" or port number. Defaults to value of 'scheme'.
+ "user": null, // [string] Authentication user name
+ "password": null, // [string] Authentication password
+
+ "sasl": {
+ "enable": true, // [bool] Enable or disable SASL
+ "mechanisms": null, // [list] List of allowed SASL mechanism names.
+ // If null the library determines the default list.
+ "allow_insecure": false // [boolean] Allow mechanisms that send clear-text passwords
+ },
+
+ // Note: it is an error to have a "tls" object unless scheme="amqps"
+ "tls": {
+ "cert": null, // [string] name of client certificate or database
+ "key": null // [string] private key or identity for client certificate
+ "ca": null, // [string] name of CA certificate or database
+ "verify": true, // [bool] if true, require a valid cert with matching host name
+ }
+ }
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b164d99c/tools/cmake/Modules/FindJsonCpp.cmake
----------------------------------------------------------------------
diff --git a/tools/cmake/Modules/FindJsonCpp.cmake b/tools/cmake/Modules/FindJsonCpp.cmake
new file mode 100644
index 0000000..083d3fc
--- /dev/null
+++ b/tools/cmake/Modules/FindJsonCpp.cmake
@@ -0,0 +1,70 @@
+#
+# 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.
+#
+
+#.rst
+# FindJsonCpp
+#----------
+#
+# Find jsoncpp include directories and libraries.
+#
+# Sets the following variables:
+#
+# JsonCpp_FOUND - True if headers and requested libraries were found
+# JsonCpp_INCLUDE_DIRS - JsonCpp include directories
+# JsonCpp_LIBRARIES - Link these to use jsoncpp.
+#
+# This module reads hints about search locations from variables::
+# JSONCPP_ROOT - Preferred installation prefix
+# JSONCPP_INCLUDEDIR - Preferred include directory e.g. <prefix>/include
+# JSONCPP_LIBRARYDIR - Preferred library directory e.g. <prefix>/lib
+
+find_package (PkgConfig)
+pkg_check_modules (PC_JsonCpp QUIET jsoncpp)
+
+find_library(JsonCpp_LIBRARY NAMES jsoncpp libjsoncpp
+ HINTS ${JSONCPP_LIBRARYDIR} ${JSONCPP_ROOT}/lib ${CMAKE_INSTALL_PREFIX}/lib
+ PATHS ${PC_JsonCpp_LIBRARY_DIRS})
+
+find_path(JsonCpp_INCLUDE_DIR NAMES json/json.h json/value.h
+ HINTS ${JSONCPP_INCLUDEDIR} ${JSONCPP_ROOT}/include ${CMAKE_INSTALL_PREFIX}/include
+ PATHS /usr/include ${PC_JsonCpp_INCLUDE_DIRS})
+
+set(JsonCpp_VERSION ${PC_JsonCpp_VERSION})
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(JsonCpp
+ REQUIRED_VARS JsonCpp_LIBRARY JsonCpp_INCLUDE_DIR
+ VERSION_VAR JsonCpp_VERSION)
+
+if (JsonCpp_FOUND)
+ set(JsonCpp_INCLUDE_DIRS ${JsonCpp_INCLUDE_DIR})
+ set(JsonCpp_LIBRARIES ${JsonCpp_LIBRARY})
+
+ if (NOT TARGET JsonCpp::JsonCpp)
+ add_library(JsonCpp::JsonCpp UNKNOWN IMPORTED)
+ set_target_properties(JsonCpp::JsonCpp
+ PROPERTIES
+ IMPORTED_LOCATION "${JsonCpp_LIBRARY}"
+ INTERFACE_INCLUDE_DIRECTORIES "${JsonCpp_INCLUDE_DIR}"
+ )
+ endif ()
+
+endif ()
+
+mark_as_advanced (JsonCpp_LIBRARY JsonCpp_INCLUDE_DIR)
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org