1 /* 2 Copyright (c) DataStax, Inc. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 #ifndef DATASTAX_INTERNAL_CLUSTER_CONNECTOR_HPP 18 #define DATASTAX_INTERNAL_CLUSTER_CONNECTOR_HPP 19 20 #include "callback.hpp" 21 #include "cluster.hpp" 22 #include "cluster_metadata_resolver.hpp" 23 #include "resolver.hpp" 24 25 namespace datastax { namespace internal { 26 27 class Random; 28 29 namespace core { 30 31 class Metrics; 32 33 /** 34 * A connector that handles connecting to a cluster. It handles DNS and error 35 * handling for multiple contact points. It attempts to connect to multiple 36 * contact points and returns after the first successful connection or it fails 37 * if no connections can be made. It also handles negotiating the highest 38 * supported server-side protocol version. 39 */ 40 class ClusterConnector : public RefCounted<ClusterConnector> { 41 public: 42 typedef SharedRefPtr<ClusterConnector> Ptr; 43 44 typedef internal::Callback<void, ClusterConnector*> Callback; 45 46 enum ClusterError { 47 CLUSTER_OK, 48 CLUSTER_CANCELED, 49 CLUSTER_ERROR_INVALID_PROTOCOL, 50 CLUSTER_ERROR_SSL_ERROR, 51 CLUSTER_ERROR_AUTH_ERROR, 52 CLUSTER_ERROR_NO_HOSTS_AVAILABLE 53 }; 54 55 /** 56 * Constructor. 57 * 58 * @param contact_points A list of hosts (IP addresses or hostname strings) 59 * that seed connection to the cluster. 60 * @param protocol_version The initial protocol version to try. 61 * @param callback A callback that is called when a connection to a contact 62 * point is established, if an error occurred, or all contact points failed. 63 */ 64 ClusterConnector(const AddressVec& contact_points, ProtocolVersion protocol_version, 65 const Callback& callback); 66 67 /** 68 * Set the cluster listener to use for handle cluster events. 69 * 70 * @param listener A listener that handles cluster events. 71 * @return The connector to chain calls. 72 */ 73 ClusterConnector* with_listener(ClusterListener* listener); 74 75 /** 76 * Set the random object to use for shuffling the contact points and load 77 * balancing policies. The random object must live for the duration of the 78 * connection process. 79 * 80 * @param random A random object. 81 * @return The connector to chain calls. 82 */ 83 ClusterConnector* with_random(Random* random); 84 85 /** 86 * Set the metrics object to use to record metrics for the control connection. 87 * 88 * @param metrics A metrics object. 89 * @return The connector to chain calls. 90 */ 91 ClusterConnector* with_metrics(Metrics* metrics); 92 93 /** 94 * Set the cluster and underlying control connection settings. 95 * 96 * @param The settings to use for connecting the cluster. 97 * @return The connector to chain calls. 98 */ with_settings(const ClusterSettings & settings)99 ClusterConnector* with_settings(const ClusterSettings& settings) { 100 settings_ = settings; 101 return this; 102 } 103 104 /** 105 * Connect to the cluster. 106 * 107 * @param event_loop The event loop to use for connecting to the cluster. 108 */ 109 void connect(EventLoop* event_loop); 110 111 /** 112 * Cancel the connection process. 113 */ 114 void cancel(); 115 116 /** 117 * Release the cluster from the connector. If not released in the callback 118 * the cluster will automatically be closed. 119 * 120 * @return The cluster object for this connector. This returns a null object 121 * if the cluster is not connected or an error occurred. 122 */ 123 Cluster::Ptr release_cluster(); 124 125 public: protocol_version() const126 ProtocolVersion protocol_version() const { return protocol_version_; } 127 is_ok() const128 bool is_ok() const { return error_code_ == CLUSTER_OK; } is_canceled() const129 bool is_canceled() const { return error_code_ == CLUSTER_CANCELED; } 130 error_code() const131 ClusterError error_code() const { return error_code_; } error_message() const132 const String& error_message() const { return error_message_; } ssl_error_code()133 CassError ssl_error_code() { return ssl_error_code_; } 134 135 private: 136 friend class RunResolveAndConnectCluster; 137 friend class RunCancelCluster; 138 139 private: 140 void internal_resolve_and_connect(); 141 void internal_connect(const Address& address, ProtocolVersion version); 142 void internal_cancel(); 143 144 void finish(); 145 void maybe_finish(); 146 147 void on_error(ClusterError code, const String& message); 148 void on_resolve(ClusterMetadataResolver* resolver); 149 void on_connect(ControlConnector* connector); 150 151 private: 152 class ConnectorMap : public DenseHashMap<Address, ControlConnector::Ptr> { 153 public: ConnectorMap()154 ConnectorMap() { 155 set_empty_key(Address::EMPTY_KEY); 156 set_deleted_key(Address::DELETED_KEY); 157 } 158 }; 159 160 private: 161 Cluster::Ptr cluster_; 162 ClusterMetadataResolver::Ptr resolver_; 163 ConnectorMap connectors_; 164 size_t remaining_connector_count_; 165 AddressVec contact_points_; 166 ProtocolVersion protocol_version_; 167 ClusterListener* listener_; 168 EventLoop* event_loop_; 169 Random* random_; 170 Metrics* metrics_; 171 String local_dc_; 172 ClusterSettings settings_; 173 174 Callback callback_; 175 176 ClusterError error_code_; 177 String error_message_; 178 CassError ssl_error_code_; 179 }; 180 181 } // namespace core 182 }} // namespace datastax::internal 183 184 #endif 185