// taken from muduo // Copyright 2010, Shuo Chen. All rights reserved. // http://code.google.com/p/muduo/ // // Use of this source code is governed by a BSD-style license // that can be found in the License file. // Author: Shuo Chen (chenshuo at chenshuo dot com) // // This is a public header file, it must only include public header files. // Copyright 2016, Tao An. All rights reserved. // // Use of this source code is governed by a BSD-style license // that can be found in the License file. // Author: Tao An #pragma once #include #include #include #include #include #include #include #include namespace trantor { class Connector; using ConnectorPtr = std::shared_ptr; class SSLContext; /** * @brief This class represents a TCP client. * */ class TRANTOR_EXPORT TcpClient : NonCopyable { public: /** * @brief Construct a new TCP client instance. * * @param loop The event loop in which the client runs. * @param serverAddr The address of the server. * @param nameArg The name of the client. */ TcpClient(EventLoop *loop, const InetAddress &serverAddr, const std::string &nameArg); ~TcpClient(); /** * @brief Connect to the server. * */ void connect(); /** * @brief Disconnect from the server. * */ void disconnect(); /** * @brief Stop connecting to the server. * */ void stop(); /** * @brief Get the TCP connection to the server. * * @return TcpConnectionPtr */ TcpConnectionPtr connection() const { std::lock_guard lock(mutex_); return connection_; } /** * @brief Get the event loop. * * @return EventLoop* */ EventLoop *getLoop() const { return loop_; } /** * @brief Check whether the client re-connect to the server. * * @return true * @return false */ bool retry() const { return retry_; } /** * @brief Enable retrying. * */ void enableRetry() { retry_ = true; } /** * @brief Get the name of the client. * * @return const std::string& */ const std::string &name() const { return name_; } /** * @brief Set the connection callback. * * @param cb The callback is called when the connection to the server is * established or closed. */ void setConnectionCallback(const ConnectionCallback &cb) { connectionCallback_ = cb; } void setConnectionCallback(ConnectionCallback &&cb) { connectionCallback_ = std::move(cb); } /** * @brief Set the connection error callback. * * @param cb The callback is called when an error occurs during connecting * to the server. */ void setConnectionErrorCallback(const ConnectionErrorCallback &cb) { connectionErrorCallback_ = cb; } /** * @brief Set the message callback. * * @param cb The callback is called when some data is received from the * server. */ void setMessageCallback(const RecvMessageCallback &cb) { messageCallback_ = cb; } void setMessageCallback(RecvMessageCallback &&cb) { messageCallback_ = std::move(cb); } /// Set write complete callback. /// Not thread safe. /** * @brief Set the write complete callback. * * @param cb The callback is called when data to send is written to the * socket. */ void setWriteCompleteCallback(const WriteCompleteCallback &cb) { writeCompleteCallback_ = cb; } void setWriteCompleteCallback(WriteCompleteCallback &&cb) { writeCompleteCallback_ = std::move(cb); } /** * @brief Set the callback for errors of SSL * @param cb The callback is called when an SSL error occurs. */ void setSSLErrorCallback(const SSLErrorCallback &cb) { sslErrorCallback_ = cb; } void setSSLErrorCallback(SSLErrorCallback &&cb) { sslErrorCallback_ = std::move(cb); } /** * @brief Enable SSL encryption. * @param useOldTLS If true, the TLS 1.0 and 1.1 are supported by the * client. * @param validateCert If true, we try to validate if the peer's SSL cert * is valid. * @param hostname The server hostname for SNI. If it is empty, the SNI is * not used. * @param sslConfCmds The commands used to call the SSL_CONF_cmd function in * OpenSSL. * @note It's well known that TLS 1.0 and 1.1 are not considered secure in * 2020. And it's a good practice to only use TLS 1.2 and above. */ void enableSSL(bool useOldTLS = false, bool validateCert = true, std::string hostname = "", const std::vector> &sslConfCmds = {}); private: /// Not thread safe, but in loop void newConnection(int sockfd); /// Not thread safe, but in loop void removeConnection(const TcpConnectionPtr &conn); EventLoop *loop_; ConnectorPtr connector_; // avoid revealing Connector const std::string name_; ConnectionCallback connectionCallback_; ConnectionErrorCallback connectionErrorCallback_; RecvMessageCallback messageCallback_; WriteCompleteCallback writeCompleteCallback_; SSLErrorCallback sslErrorCallback_; std::atomic_bool retry_; // atomic std::atomic_bool connect_; // atomic // always in loop thread mutable std::mutex mutex_; TcpConnectionPtr connection_; // @GuardedBy mutex_ std::shared_ptr sslCtxPtr_; bool validateCert_{false}; std::string SSLHostName_; #ifndef _WIN32 class IgnoreSigPipe { public: IgnoreSigPipe() { ::signal(SIGPIPE, SIG_IGN); } }; static IgnoreSigPipe initObj; #endif }; } // namespace trantor