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