1 /* 2 Copyright (c) 2014-2017 DataStax 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_CONNECTOR_HPP 18 #define DATASTAX_INTERNAL_CONNECTOR_HPP 19 20 #include <uv.h> 21 22 #include "address.hpp" 23 #include "callback.hpp" 24 #include "ref_counted.hpp" 25 26 namespace datastax { namespace internal { namespace core { 27 28 /** 29 * A wrapper for uv_connect that handles connecting a TCP connection. 30 */ 31 class TcpConnector : public RefCounted<TcpConnector> { 32 public: 33 typedef SharedRefPtr<TcpConnector> Ptr; 34 35 typedef internal::Callback<void, TcpConnector*> Callback; 36 37 enum Status { NEW, CONNECTING, FAILED_BAD_PARAM, FAILED_TO_CONNECT, CANCELED, SUCCESS }; 38 39 /** 40 * Constructor 41 * 42 * @param address The address to connect to. 43 */ TcpConnector(const Address & address)44 TcpConnector(const Address& address) 45 : address_(address) 46 , status_(NEW) 47 , uv_status_(-1) { 48 req_.data = this; 49 } 50 51 /** 52 * Connect the given TCP handle. 53 * 54 * @param handle The handle to connect. 55 * @param callback A callback that's called when the handle is connected or 56 * an error occurs. 57 */ connect(uv_tcp_t * handle,const Callback & callback)58 void connect(uv_tcp_t* handle, const Callback& callback) { 59 int rc = 0; 60 61 inc_ref(); // For the event loop 62 63 callback_ = callback; 64 status_ = CONNECTING; 65 66 Address::SocketStorage storage; 67 rc = uv_tcp_connect(&req_, handle, address_.to_sockaddr(&storage), on_connect); 68 69 if (rc != 0) { 70 status_ = FAILED_BAD_PARAM; 71 uv_status_ = rc; 72 callback_(this); 73 dec_ref(); 74 } 75 } 76 77 /** 78 * Cancel the connection process. 79 */ cancel()80 void cancel() { 81 if (status_ == CONNECTING) { 82 uv_cancel(reinterpret_cast<uv_req_t*>(&req_)); 83 status_ = CANCELED; 84 } 85 } 86 87 public: loop()88 uv_loop_t* loop() { return req_.handle->loop; } 89 is_success()90 bool is_success() { return status_ == SUCCESS; } is_canceled()91 bool is_canceled() { return status_ == CANCELED; } status()92 Status status() { return status_; } uv_status()93 int uv_status() { return uv_status_; } 94 address()95 const Address& address() { return address_; } 96 97 private: on_connect(uv_connect_t * req,int status)98 static void on_connect(uv_connect_t* req, int status) { 99 TcpConnector* connector = static_cast<TcpConnector*>(req->data); 100 if (connector->status_ == CONNECTING) { 101 if (status == 0) { 102 connector->status_ = SUCCESS; 103 } else { 104 connector->status_ = FAILED_TO_CONNECT; 105 } 106 } 107 108 connector->uv_status_ = status; 109 connector->callback_(connector); 110 connector->dec_ref(); 111 } 112 113 private: 114 uv_connect_t req_; 115 Address address_; 116 Callback callback_; 117 Status status_; 118 int uv_status_; 119 }; 120 121 }}} // namespace datastax::internal::core 122 123 #endif 124