void redis_connection::connect(const std::string &host, std::size_t port, const disconnection_handler_t &client_disconnection_handler, const reply_callback_t &client_reply_callback, std::uint32_t timeout_ms) { try { __CPP_REDIS_LOG(debug, "cpp_redis::network::redis_connection attempts to connect"); /** * connect client */ m_client->connect(host, (uint32_t) port, timeout_ms); m_client->set_on_disconnection_handler(std::bind(&redis_connection::tcp_client_disconnection_handler, this)); /** * start to read asynchronously */ tcp_client_iface::read_request request = {__CPP_REDIS_READ_SIZE, std::bind(&redis_connection::tcp_client_receive_handler, this, std::placeholders::_1)}; m_client->async_read(request); __CPP_REDIS_LOG(debug, "cpp_redis::network::redis_connection connected"); } catch (const std::exception &e) { __CPP_REDIS_LOG(error, std::string("cpp_redis::network::redis_connection ") + e.what()); throw redis_error(e.what()); } m_reply_callback = client_reply_callback; m_disconnection_handler = client_disconnection_handler; }
void tcp_client::connect(const std::string& host, unsigned int port, const disconnection_handler_t& disconnection_handler, const receive_handler_t& receive_handler) { if (m_is_connected) return ; //! create the socket m_fd = socket(AF_INET, SOCK_STREAM, 0); if (m_fd < 0) throw redis_error("Can't open a socket"); //! get the server's DNS entry struct hostent *server = gethostbyname(host.c_str()); if (not server) throw redis_error("No such host: " + host); //! build the server's Internet address struct sockaddr_in server_addr; std::memset(&server_addr, 0, sizeof(server_addr)); std::memcpy(server->h_addr, &server_addr.sin_addr.s_addr, server->h_length); server_addr.sin_port = htons(port); server_addr.sin_family = AF_INET; //! create a connection with the server if (::connect(m_fd, reinterpret_cast<const struct sockaddr *>(&server_addr), sizeof(server_addr)) < 0) throw redis_error("Fail to connect to " + host + ":" + std::to_string(port)); //! add fd to the io_service and set the disconnection & recv handlers m_disconnection_handler = disconnection_handler; m_receive_handler = receive_handler; m_io_service.track(m_fd, std::bind(&tcp_client::io_service_disconnection_handler, this, std::placeholders::_1)); m_is_connected = true; //! start async read async_read(); }
void tcp_client::connect(const std::string& host, unsigned int port) { if (m_is_connected) throw redis_error("Already connected"); std::condition_variable conn_cond_var; //! resolve host name boost::asio::ip::tcp::resolver resolver(m_io_service.get()); boost::asio::ip::tcp::resolver::query query(host, std::to_string(port)); boost::asio::ip::tcp::resolver::iterator iter = resolver.resolve(query); boost::asio::ip::tcp::endpoint endpoint = iter->endpoint(); //! async connect std::atomic_bool is_notified(false); m_socket.async_connect(endpoint, [&](boost::system::error_code error) { if (not error) { m_is_connected = true; async_read(); } is_notified = true; conn_cond_var.notify_one(); }); //! start loop and wait for async connect result std::mutex conn_mutex; std::unique_lock<std::mutex> lock(conn_mutex); m_io_service.run(); if (not is_notified) conn_cond_var.wait(lock); if (not m_is_connected) throw redis_error("Fail to connect to " + host + ":" + std::to_string(port)); }
bool array_builder::fetch_array_size(std::string& buffer) { if (m_int_builder.reply_ready()) return true; m_int_builder << buffer; if (not m_int_builder.reply_ready()) return false; int size = m_int_builder.get_integer(); if (size < 0) throw redis_error("Invalid array size"); else if (size == 0) m_reply_ready = true; m_array_size = size; return true; }
void tcp_client::send(const std::vector<char>& buffer) { if (not m_is_connected) throw redis_error("Not connected"); if (not buffer.size()) return ; std::lock_guard<std::mutex> lock(m_write_buffer_mutex); bool bytes_in_buffer = m_write_buffer.size() > 0; //! concat buffer m_write_buffer.insert(m_write_buffer.end(), buffer.begin(), buffer.end()); //! if there were already bytes in buffer, simply return //! async_write callback will process the new buffer if (bytes_in_buffer) return ; async_write(); }
void tcp_client::disconnect(void) { if (not m_is_connected) throw redis_error("Not connected"); m_is_connected = false; std::mutex close_socket_mutex; std::condition_variable close_socket_cond_var; std::unique_lock<std::mutex> lock(close_socket_mutex); std::atomic_bool is_notified(false); m_io_service.post([this, &close_socket_cond_var, &is_notified]() { m_socket.close(); is_notified = true; close_socket_cond_var.notify_one(); }); if (not is_notified) close_socket_cond_var.wait(lock); }
/** * commit pipelined transaction */ redis_connection & redis_connection::commit() { std::lock_guard<std::mutex> lock(m_buffer_mutex); /** * ensure buffer is cleared */ __CPP_REDIS_LOG(debug, "cpp_redis::network::redis_connection attempts to send pipelined commands"); std::string buffer = std::move(m_buffer); try { tcp_client_iface::write_request request = {std::vector<char>{buffer.begin(), buffer.end()}, nullptr}; m_client->async_write(request); } catch (const std::exception &e) { __CPP_REDIS_LOG(error, std::string("cpp_redis::network::redis_connection ") + e.what()); throw redis_error(e.what()); } __CPP_REDIS_LOG(debug, "cpp_redis::network::redis_connection sent pipelined commands"); return *this; }