22#include <boost/enable_shared_from_this.hpp> 
   23#include <boost/weak_ptr.hpp> 
   39using namespace boost::posix_time;
 
   41namespace ph = std::placeholders;
 
   48constexpr size_t MAX_LOGGED_MESSAGE_SIZE = 1024;
 
   51typedef std::function<void(boost::system::error_code ec, 
size_t length)>
 
   67    SocketCallback(SocketCallbackFunction socket_callback)
 
   68        : callback_(socket_callback) {
 
   77    void operator()(boost::system::error_code ec, 
size_t length = 0) {
 
   78        if (ec.value() == boost::asio::error::operation_aborted) {
 
   81        callback_(ec, length);
 
   94typedef boost::shared_ptr<ConnectionPool> ConnectionPoolPtr;
 
  111class Connection : 
public boost::enable_shared_from_this<Connection> {
 
  123                        const ConnectionPoolPtr& conn_pool,
 
  149                       const long request_timeout,
 
  161    bool isTransactionOngoing()
 const {
 
  168    bool isClosed()
 const {
 
  176    void isClosedByPeer();
 
  183    bool isMySocket(
int socket_fd) 
const;
 
  200    bool checkPrematureTimeout(
const uint64_t transid);
 
  226                               const long request_timeout,
 
  235    void closeInternal();
 
  243    void isClosedByPeerInternal();
 
  262    bool checkPrematureTimeoutInternal(
const uint64_t transid);
 
  281    void terminate(
const boost::system::error_code& ec,
 
  282                   const std::string& parsing_error = 
"");
 
  295    void terminateInternal(
const boost::system::error_code& ec,
 
  296                           const std::string& parsing_error = 
"");
 
  304    bool runParser(
const boost::system::error_code& ec, 
size_t length);
 
  314    bool runParserInternal(
const boost::system::error_code& ec, 
size_t length);
 
  319    void scheduleTimer(
const long request_timeout);
 
  326    void doHandshake(
const uint64_t transid);
 
  333    void doSend(
const uint64_t transid);
 
  340    void doReceive(
const uint64_t transid);
 
  353                         const uint64_t transid,
 
  354                         const boost::system::error_code& ec);
 
  366                           const uint64_t transid,
 
  367                           const boost::system::error_code& ec);
 
  379    void sendCallback(
const uint64_t transid, 
const boost::system::error_code& ec,
 
  388    void receiveCallback(
const uint64_t transid, 
const boost::system::error_code& ec,
 
  392    void timerCallback();
 
  403    void closeCallback(
const bool clear = 
false);
 
  412    boost::weak_ptr<ConnectionPool> conn_pool_;
 
  421    std::shared_ptr<TCPSocket<SocketCallback>> tcp_socket_;
 
  424    std::shared_ptr<TLSSocket<SocketCallback>> tls_socket_;
 
  445    std::array<char, 32768> input_buf_;
 
  448    uint64_t current_transid_;
 
  457    std::atomic<bool> started_;
 
  460    std::atomic<bool> need_handshake_;
 
  463    std::atomic<bool> closed_;
 
  470typedef boost::shared_ptr<Connection> ConnectionPtr;
 
  479class ConnectionPool : 
public boost::enable_shared_from_this<ConnectionPool> {
 
  488    explicit ConnectionPool(
const IOServicePtr& io_service, 
size_t max_url_connections)
 
  489        : io_service_(io_service), destinations_(), pool_mutex_(),
 
  490          max_url_connections_(max_url_connections) {
 
  505    void processNextRequest(
const Url& url, 
const TlsContextPtr& tls_context) {
 
  507            std::lock_guard<std::mutex> lk(pool_mutex_);
 
  508            return (processNextRequestInternal(url, tls_context));
 
  510            return (processNextRequestInternal(url, tls_context));
 
  519    void postProcessNextRequest(
const Url& url,
 
  521        io_service_->post(std::bind(&ConnectionPool::processNextRequest,
 
  522                                    shared_from_this(), url, tls_context));
 
  545    void queueRequest(
const Url& url,
 
  549                      const long request_timeout,
 
  555            std::lock_guard<std::mutex> lk(pool_mutex_);
 
  556            return (queueRequestInternal(url, tls_context, request, response,
 
  557                                         request_timeout, request_callback,
 
  558                                         connect_callback, handshake_callback,
 
  561            return (queueRequestInternal(url, tls_context, request, response,
 
  562                                         request_timeout, request_callback,
 
  563                                         connect_callback, handshake_callback,
 
  572            std::lock_guard<std::mutex> lk(pool_mutex_);
 
  591    void closeIfOutOfBand(
int socket_fd) {
 
  593            std::lock_guard<std::mutex> lk(pool_mutex_);
 
  594            closeIfOutOfBandInternal(socket_fd);
 
  596            closeIfOutOfBandInternal(socket_fd);
 
  609    void processNextRequestInternal(
const Url& url,
 
  613        DestinationPtr destination = findDestination(url, tls_context);
 
  616            destination->garbageCollectConnections();
 
  617            if (!destination->queueEmpty()) {
 
  620                ConnectionPtr connection = destination->getIdleConnection();
 
  623                    if (destination->connectionsFull()) {
 
  628                    connection.reset(
new Connection(io_service_, tls_context,
 
  629                                                    shared_from_this(), url));
 
  630                    destination->addConnection(connection);
 
  635                RequestDescriptor desc = destination->popNextRequest();
 
  636                connection->doTransaction(desc.request_, desc.response_,
 
  637                                          desc.request_timeout_, desc.callback_,
 
  638                                          desc.connect_callback_,
 
  639                                          desc.handshake_callback_,
 
  640                                          desc.close_callback_);
 
  667    void queueRequestInternal(
const Url& url,
 
  671                              const long request_timeout,
 
  676        ConnectionPtr connection;
 
  678        DestinationPtr destination = findDestination(url, tls_context);
 
  681            destination->garbageCollectConnections();
 
  683            connection = destination->getIdleConnection();
 
  686            destination = addDestination(url, tls_context);
 
  690            if (destination->connectionsFull()) {
 
  692                destination->pushRequest(RequestDescriptor(request, response,
 
  702            connection.reset(
new Connection(io_service_, tls_context,
 
  703                                            shared_from_this(), url));
 
  704            destination->addConnection(connection);
 
  708        connection->doTransaction(request, response, request_timeout, request_callback,
 
  709                                  connect_callback, handshake_callback, close_callback);
 
  716    void closeAllInternal() {
 
  717        for (
auto const& destination : destinations_) {
 
  718            destination.second->closeAllConnections();
 
  721        destinations_.clear();
 
  738    void closeIfOutOfBandInternal(
int socket_fd) {
 
  739        for (
auto const& destination : destinations_) {
 
  741            ConnectionPtr connection = destination.second->findBySocketFd(socket_fd);
 
  743                if (!connection->isTransactionOngoing()) {
 
  749                    destination.second->closeConnection(connection);
 
  759    struct RequestDescriptor {
 
  775                          const long& request_timeout,
 
  780            : request_(request), response_(response),
 
  781              request_timeout_(request_timeout), callback_(callback),
 
  782              connect_callback_(connect_callback),
 
  783              handshake_callback_(handshake_callback),
 
  784              close_callback_(close_callback) {
 
  794        long request_timeout_;
 
  810    typedef std::pair<Url, TlsContextPtr> DestinationDescriptor;
 
  816        const size_t QUEUE_SIZE_THRESHOLD = 2048;
 
  818        const int QUEUE_WARN_SECS = 5;
 
  826        Destination(Url 
const& url, 
TlsContextPtr tls_context, 
size_t max_connections)
 
  827            : url_(url), tls_context_(tls_context),
 
  828              max_connections_(max_connections), connections_(), queue_(),
 
  829              last_queue_warn_time_(min_date_time), last_queue_size_(0) {
 
  834            closeAllConnections();
 
  844        void addConnection(ConnectionPtr connection) {
 
  845            if (connectionsFull()) {
 
  846                isc_throw(BadValue, 
"URL: " << url_.toText()
 
  847                      << 
", already at maximum connections: " 
  848                      << max_connections_);
 
  851            connections_.push_back(connection);
 
  858        void closeConnection(ConnectionPtr connection) {
 
  859            for (
auto it = connections_.begin(); it != connections_.end(); ++it) {
 
  860                if (*it == connection) {
 
  862                    connections_.erase(it);
 
  870        void closeAllConnections() {
 
  872            while (!queue_.empty()) {
 
  876            for (
auto const& connection : connections_) {
 
  880            connections_.clear();
 
  906        void garbageCollectConnections() {
 
  907            for (
auto it = connections_.begin(); it != connections_.end();) {
 
  908                (*it)->isClosedByPeer();
 
  909                if (!(*it)->isClosed()) {
 
  912                    it = connections_.erase(it);
 
  928        ConnectionPtr getIdleConnection() {
 
  929            for (
auto const& connection : connections_) {
 
  930                if (!connection->isTransactionOngoing() &&
 
  931                    !connection->isClosed()) {
 
  936            return (ConnectionPtr());
 
  945        ConnectionPtr findBySocketFd(
int socket_fd) {
 
  946            for (
auto const& connection : connections_) {
 
  947                if (connection->isMySocket(socket_fd)) {
 
  952            return (ConnectionPtr());
 
  958        bool connectionsEmpty() {
 
  959            return (connections_.empty());
 
  965        bool connectionsFull() {
 
  966            return (connections_.size() >= max_connections_);
 
  972        size_t connectionCount() {
 
  973            return (connections_.size());
 
  979        size_t getMaxConnections()
 const {
 
  980            return (max_connections_);
 
  986        bool queueEmpty()
 const {
 
  987            return (queue_.empty());
 
  996        void pushRequest(RequestDescriptor 
const& desc) {
 
  998            size_t size = queue_.size();
 
 1001            if ((size > QUEUE_SIZE_THRESHOLD) && (size > last_queue_size_)) {
 
 1002                ptime now = microsec_clock::universal_time();
 
 1003                if ((now - last_queue_warn_time_) > seconds(QUEUE_WARN_SECS)) {
 
 1008                    last_queue_warn_time_ = now;
 
 1013            last_queue_size_ = size;
 
 1019        RequestDescriptor popNextRequest() {
 
 1020            if (queue_.empty()) {
 
 1021                isc_throw(InvalidOperation, 
"cannot pop, queue is empty");
 
 1024            RequestDescriptor desc = queue_.front();
 
 1037        size_t max_connections_;
 
 1040        std::list<ConnectionPtr> connections_;
 
 1043        std::queue<RequestDescriptor> queue_;
 
 1046        ptime last_queue_warn_time_;
 
 1049        size_t last_queue_size_;
 
 1053    typedef boost::shared_ptr<Destination> DestinationPtr;
 
 1062    DestinationPtr addDestination(
const Url& url,
 
 1064        const DestinationDescriptor& desc = std::make_pair(url, tls_context);
 
 1065        DestinationPtr destination(
new Destination(url, tls_context,
 
 1066                                                   max_url_connections_));
 
 1067        destinations_[desc] = destination;
 
 1068        return (destination);
 
 1079    DestinationPtr findDestination(
const Url& url,
 
 1081        const DestinationDescriptor& desc = std::make_pair(url, tls_context);
 
 1082        auto it = destinations_.find(desc);
 
 1083        if (it != destinations_.end()) {
 
 1084            return (it->second);
 
 1087        return (DestinationPtr());
 
 1101    void removeDestination(
const Url& url,
 
 1103        const DestinationDescriptor& desc = std::make_pair(url, tls_context);
 
 1104        auto it = destinations_.find(desc);
 
 1105        if (it != destinations_.end()) {
 
 1106            it->second->closeAllConnections();
 
 1107            destinations_.erase(it);
 
 1115    std::map<DestinationDescriptor, DestinationPtr> destinations_;
 
 1118    std::mutex pool_mutex_;
 
 1121    size_t max_url_connections_;
 
 1126                       const ConnectionPoolPtr& conn_pool,
 
 1128    : io_service_(io_service), conn_pool_(conn_pool), url_(url),
 
 1129      tls_context_(tls_context), tcp_socket_(), tls_socket_(),
 
 1130      timer_(new IntervalTimer(io_service)), current_request_(),
 
 1131      current_response_(), parser_(), current_callback_(), buf_(), input_buf_(),
 
 1132      current_transid_(0), close_callback_(), started_(false),
 
 1133      need_handshake_(false), closed_(false) {
 
 1139        need_handshake_ = 
true;
 
 1143Connection::~Connection() {
 
 1148Connection::resetState() {
 
 1150    current_request_.reset();
 
 1151    current_response_.reset();
 
 1157Connection::closeCallback(
const bool clear) {
 
 1158    if (close_callback_) {
 
 1161                close_callback_(tcp_socket_->getNative());
 
 1162            } 
else if (tls_socket_) {
 
 1163                close_callback_(tls_socket_->getNative());
 
 1166                          "internal error: can't find a socket to close");
 
 1179Connection::isClosedByPeer() {
 
 1181    if (started_ || closed_) {
 
 1186        std::lock_guard<std::mutex> lk(mutex_);
 
 1187        isClosedByPeerInternal();
 
 1189        isClosedByPeerInternal();
 
 1194Connection::isClosedByPeerInternal() {
 
 1203        if (tcp_socket_->getASIOSocket().is_open() &&
 
 1204            !tcp_socket_->isUsable()) {
 
 1207            tcp_socket_->close();
 
 1209    } 
else if (tls_socket_) {
 
 1210        if (tls_socket_->getASIOSocket().is_open() &&
 
 1211            !tls_socket_->isUsable()) {
 
 1214            tls_socket_->close();
 
 1217        isc_throw(Unexpected, 
"internal error: can't find the sending socket");
 
 1224                          const long request_timeout,
 
 1230        std::lock_guard<std::mutex> lk(mutex_);
 
 1231        doTransactionInternal(request, response, request_timeout,
 
 1232                              callback, connect_callback, handshake_callback,
 
 1235        doTransactionInternal(request, response, request_timeout,
 
 1236                              callback, connect_callback, handshake_callback,
 
 1244                                  const long request_timeout,
 
 1251        current_request_ = request;
 
 1252        current_response_ = response;
 
 1253        parser_.reset(
new HttpResponseParser(*current_response_));
 
 1254        parser_->initModel();
 
 1255        current_callback_ = callback;
 
 1256        handshake_callback_ = handshake_callback;
 
 1257        close_callback_ = close_callback;
 
 1262        buf_ = request->toString();
 
 1266            .arg(request->toBriefString())
 
 1267            .arg(url_.toText());
 
 1273                                                             MAX_LOGGED_MESSAGE_SIZE));
 
 1276        scheduleTimer(request_timeout);
 
 1281        TCPEndpoint endpoint(url_.getStrippedHostname(),
 
 1282                             static_cast<unsigned short>(url_.getPort()));
 
 1283        SocketCallback socket_cb(std::bind(&Connection::connectCallback, shared_from_this(),
 
 1284                                           connect_callback, current_transid_,
 
 1289            tcp_socket_->open(&endpoint, socket_cb);
 
 1293            tls_socket_->open(&endpoint, socket_cb);
 
 1298        isc_throw(Unexpected, 
"internal error: can't find a socket to open");
 
 1300    } 
catch (
const std::exception& ex) {
 
 1307Connection::close() {
 
 1309        std::lock_guard<std::mutex> lk(mutex_);
 
 1310        return (closeInternal());
 
 1312        return (closeInternal());
 
 1317Connection::closeInternal() {
 
 1319    closeCallback(
true);
 
 1324        tcp_socket_->close();
 
 1327        tls_socket_->close();
 
 1334Connection::isMySocket(
int socket_fd)
 const {
 
 1336        return (tcp_socket_->getNative() == socket_fd);
 
 1337    } 
else if (tls_socket_) {
 
 1338        return (tls_socket_->getNative() == socket_fd);
 
 1341    std::cerr << 
"internal error: can't find my socket\n";
 
 1346Connection::checkPrematureTimeout(
const uint64_t transid) {
 
 1348        std::lock_guard<std::mutex> lk(mutex_);
 
 1349        return (checkPrematureTimeoutInternal(transid));
 
 1351        return (checkPrematureTimeoutInternal(transid));
 
 1356Connection::checkPrematureTimeoutInternal(
const uint64_t transid) {
 
 1362    if (!isTransactionOngoing() || (transid != current_transid_)) {
 
 1364                .arg(isTransactionOngoing())
 
 1366                .arg(current_transid_);
 
 1374Connection::terminate(
const boost::system::error_code& ec,
 
 1375                      const std::string& parsing_error) {
 
 1377        std::lock_guard<std::mutex> lk(mutex_);
 
 1378        terminateInternal(ec, parsing_error);
 
 1380        terminateInternal(ec, parsing_error);
 
 1385Connection::terminateInternal(
const boost::system::error_code& ec,
 
 1386                              const std::string& parsing_error) {
 
 1388    if (isTransactionOngoing()) {
 
 1392            tcp_socket_->cancel();
 
 1395            tls_socket_->cancel();
 
 1398        if (!ec && current_response_->isFinalized()) {
 
 1399            response = current_response_;
 
 1403                .arg(url_.toText());
 
 1409                     parser_->getBufferAsString(MAX_LOGGED_MESSAGE_SIZE) :
 
 1410                     "[HttpResponseParser is null]");
 
 1413            std::string err = parsing_error.empty() ? ec.message() :
 
 1423            if (!parsing_error.empty()) {
 
 1428                         parser_->getBufferAsString(MAX_LOGGED_MESSAGE_SIZE) :
 
 1429                         "[HttpResponseParser is null]");
 
 1437                UnlockGuard<std::mutex> lock(mutex_);
 
 1438                current_callback_(ec, response, parsing_error);
 
 1440                current_callback_(ec, response, parsing_error);
 
 1448            (!current_request_->isPersistent() ||
 
 1449             (ec == boost::asio::error::timed_out))) {
 
 1458    ConnectionPoolPtr conn_pool = conn_pool_.lock();
 
 1460        conn_pool->postProcessNextRequest(url_, tls_context_);
 
 1465Connection::scheduleTimer(
const long request_timeout) {
 
 1466    if (request_timeout > 0) {
 
 1467        timer_->setup(std::bind(&Connection::timerCallback, 
this), request_timeout,
 
 1473Connection::doHandshake(
const uint64_t transid) {
 
 1475    if (!need_handshake_) {
 
 1480    SocketCallback socket_cb(std::bind(&Connection::handshakeCallback,
 
 1482                                       handshake_callback_,
 
 1486       tls_socket_->handshake(socket_cb);
 
 1489        terminate(boost::asio::error::not_connected);
 
 1494Connection::doSend(
const uint64_t transid) {
 
 1495    SocketCallback socket_cb(std::bind(&Connection::sendCallback,
 
 1502            tcp_socket_->asyncSend(&buf_[0], buf_.size(), socket_cb);
 
 1507            tls_socket_->asyncSend(&buf_[0], buf_.size(), socket_cb);
 
 1512        std::cerr << 
"internal error: can't find a socket to send to\n";
 
 1514                  "internal error: can't find a socket to send to");
 
 1516        terminate(boost::asio::error::not_connected);
 
 1521Connection::doReceive(
const uint64_t transid) {
 
 1522    TCPEndpoint endpoint;
 
 1523    SocketCallback socket_cb(std::bind(&Connection::receiveCallback,
 
 1530            tcp_socket_->asyncReceive(
static_cast<void*
>(input_buf_.data()),
 
 1531                                      input_buf_.size(), 0,
 
 1532                                      &endpoint, socket_cb);
 
 1536            tls_socket_->asyncReceive(
static_cast<void*
>(input_buf_.data()),
 
 1537                                      input_buf_.size(), 0,
 
 1538                                      &endpoint, socket_cb);
 
 1542        std::cerr << 
"internal error: can't find a socket to receive from\n";
 
 1544                  "internal error: can't find a socket to receive from");
 
 1547        terminate(boost::asio::error::not_connected);
 
 1553                            const uint64_t transid,
 
 1554                            const boost::system::error_code& ec) {
 
 1555    if (checkPrematureTimeout(transid)) {
 
 1560    if (connect_callback) {
 
 1564            if (!connect_callback(ec, tcp_socket_->getNative())) {
 
 1567        } 
else if (tls_socket_) {
 
 1568            if (!connect_callback(ec, tls_socket_->getNative())) {
 
 1573            std::cerr << 
"internal error: can't find a socket to connect\n";
 
 1577    if (ec && (ec.value() == boost::asio::error::operation_aborted)) {
 
 1585        (ec.value() != boost::asio::error::in_progress) &&
 
 1586        (ec.value() != boost::asio::error::already_connected)) {
 
 1591        doHandshake(transid);
 
 1597                              const uint64_t transid,
 
 1598                              const boost::system::error_code& ec) {
 
 1599    need_handshake_ = 
false;
 
 1600    if (checkPrematureTimeout(transid)) {
 
 1605    if (handshake_callback) {
 
 1609            if (!handshake_callback(ec, tls_socket_->getNative())) {
 
 1614            std::cerr << 
"internal error: can't find TLS socket\n";
 
 1618    if (ec && (ec.value() == boost::asio::error::operation_aborted)) {
 
 1630Connection::sendCallback(
const uint64_t transid,
 
 1631                         const boost::system::error_code& ec,
 
 1633    if (checkPrematureTimeout(transid)) {
 
 1638        if (ec.value() == boost::asio::error::operation_aborted) {
 
 1643        } 
else if ((ec.value() == boost::asio::error::would_block) ||
 
 1644            (ec.value() == boost::asio::error::try_again)) {
 
 1655    scheduleTimer(timer_->getInterval());
 
 1660        buf_.erase(0, length);
 
 1674Connection::receiveCallback(
const uint64_t transid,
 
 1675                            const boost::system::error_code& ec,
 
 1677    if (checkPrematureTimeout(transid)) {
 
 1682        if (ec.value() == boost::asio::error::operation_aborted) {
 
 1688        if ((ec.value() != boost::asio::error::try_again) &&
 
 1689            (ec.value() != boost::asio::error::would_block)) {
 
 1701    scheduleTimer(timer_->getInterval());
 
 1703    if (runParser(ec, length)) {
 
 1709Connection::runParser(
const boost::system::error_code& ec, 
size_t length) {
 
 1711        std::lock_guard<std::mutex> lk(mutex_);
 
 1712        return (runParserInternal(ec, length));
 
 1714        return (runParserInternal(ec, length));
 
 1719Connection::runParserInternal(
const boost::system::error_code& ec,
 
 1723        parser_->postBuffer(
static_cast<void*
>(input_buf_.data()), length);
 
 1728    if (parser_->needData()) {
 
 1731    } 
else if (parser_->httpParseOk()) {
 
 1735            current_response_->finalize();
 
 1736            terminateInternal(ec);
 
 1738        } 
catch (
const std::exception& ex) {
 
 1740            terminateInternal(ec, ex.what());
 
 1746        terminateInternal(ec, parser_->getErrorMessage());
 
 1753Connection::timerCallback() {
 
 1755    terminate(boost::asio::error::timed_out);
 
 1790                   bool defer_thread_start = 
false)
 
 1791        : thread_pool_size_(thread_pool_size), thread_pool_() {
 
 1792        if (thread_pool_size_ > 0) {
 
 1794            thread_io_service_.reset(
new IOService());
 
 1798            conn_pool_.reset(
new ConnectionPool(thread_io_service_, thread_pool_size_));
 
 1802                                                       defer_thread_start));
 
 1805                     .arg(thread_pool_size_);
 
 1809            conn_pool_.reset(
new ConnectionPool(io_service, 1));
 
 
 1827            thread_pool_->checkPausePermissions();
 
 
 1834            thread_pool_->run();
 
 
 1846            thread_pool_->stop();
 
 1849        if (thread_io_service_) {
 
 1850            thread_io_service_->stopAndPoll();
 
 1851            thread_io_service_->stop();
 
 
 1860        if (!thread_pool_) {
 
 1865        thread_pool_->pause();
 
 
 1873        if (!thread_pool_) {
 
 1878        thread_pool_->run();
 
 
 1887            return (thread_pool_->isRunning());
 
 
 1899            return (thread_pool_->isStopped());
 
 
 1911            return (thread_pool_->isPaused());
 
 
 1922        return (thread_io_service_);
 
 
 1929        return (thread_pool_size_);
 
 
 1936        if (!thread_pool_) {
 
 1939        return (thread_pool_->getThreadCount());
 
 
 1948    size_t thread_pool_size_;
 
 
 1959                       size_t thread_pool_size, 
bool defer_thread_start) {
 
 1960    if (!multi_threading_enabled && thread_pool_size) {
 
 1962                  "HttpClient thread_pool_size must be zero " 
 1963                  "when Kea core multi-threading is disabled");
 
 1967                                   defer_thread_start));
 
 
 2000    if (!request_callback) {
 
 2004    impl_->conn_pool_->queueRequest(url, tls_context, request, response,
 
 2006                                    request_callback, connect_callback,
 
 2007                                    handshake_callback, close_callback);
 
 
 2012    return (impl_->conn_pool_->closeIfOutOfBand(socket_fd));
 
 
 2022    impl_->checkPermissions();
 
 
 2042    return (impl_->getThreadIOService());
 
 
 2047    return (impl_->getThreadPoolSize());
 
 
 2052    return (impl_->getThreadCount());
 
 
 2057    return (impl_->isRunning());
 
 
 2062    return (impl_->isStopped());
 
 
 2067    return (impl_->isPaused());
 
 
A generic exception that is thrown if a function is called in a prohibited way.
The IOService class is a wrapper for the ASIO io_context class.
Implements a pausable pool of IOService driven threads.
The TCPSocket class is a concrete derived class of IOAsioSocket that represents a TCP socket.
The TLSSocket class is a concrete derived class of IOAsioSocket that represents a TLS socket.
A generic error raised by the HttpClient class.
HttpClient implementation.
ConnectionPoolPtr conn_pool_
Holds a pointer to the connection pool.
uint16_t getThreadCount()
Fetches the number of threads in the pool.
~HttpClientImpl()
Destructor.
void pause()
Pauses the client's thread pool.
uint16_t getThreadPoolSize()
Fetches the maximum size of the thread pool.
void start()
Starts running the client's thread pool, if multi-threaded.
void stop()
Close all connections, and if multi-threaded, stops the client's thread pool.
asiolink::IOServicePtr getThreadIOService()
Fetches the internal IOService used in multi-threaded mode.
void checkPermissions()
Check if the current thread can perform thread pool state transition.
bool isPaused()
Indicates if the thread pool is paused.
void resume()
Resumes running the client's thread pool.
HttpClientImpl(const IOServicePtr &io_service, size_t thread_pool_size=0, bool defer_thread_start=false)
Constructor.
bool isStopped()
Indicates if the thread pool is stopped.
bool isRunning()
Indicates if the thread pool is running.
uint16_t getThreadCount() const
Fetches the number of threads in the pool.
bool isRunning()
Indicates if the thread pool is running.
HttpClient(const asiolink::IOServicePtr &io_service, bool multi_threading_enabled, size_t thread_pool_size=0, bool defer_thread_start=false)
Constructor.
std::function< void(const boost::system::error_code &, const HttpResponsePtr &, const std::string &)> RequestHandler
Callback type used in call to HttpClient::asyncSendRequest.
void stop()
Halts client-side IO activity.
bool isPaused()
Indicates if the thread pool is paused.
void pause()
Pauses the client's thread pool.
std::function< void(const int)> CloseHandler
Optional handler invoked when client closes the connection to the server.
const asiolink::IOServicePtr getThreadIOService() const
Fetches a pointer to the internal IOService used to drive the thread-pool in multi-threaded mode.
void start()
Starts running the client's thread pool, if multi-threaded.
std::function< bool(const boost::system::error_code &, const int)> ConnectHandler
Optional handler invoked when client connects to the server.
uint16_t getThreadPoolSize() const
Fetches the maximum size of the thread pool.
std::function< bool(const boost::system::error_code &, const int)> HandshakeHandler
Optional handler invoked when client performs the TLS handshake with the server.
void closeIfOutOfBand(int socket_fd)
Closes a connection if it has an out-of-band socket event.
void resume()
Resumes running the client's thread pool.
void asyncSendRequest(const Url &url, const asiolink::TlsContextPtr &tls_context, const HttpRequestPtr &request, const HttpResponsePtr &response, const RequestHandler &request_callback, const RequestTimeout &request_timeout=RequestTimeout(10000), const ConnectHandler &connect_callback=ConnectHandler(), const HandshakeHandler &handshake_callback=HandshakeHandler(), const CloseHandler &close_callback=CloseHandler())
Queues new asynchronous HTTP request for a given URL.
bool isStopped()
Indicates if the thread pool is stopped.
void checkPermissions()
Check if the current thread can perform thread pool state transition.
static std::string logFormatHttpMessage(const std::string &message, const size_t limit=0)
Formats provided HTTP message for logging.
Scheme getScheme() const
Returns parsed scheme.
bool isValid() const
Checks if the URL is valid.
static MultiThreadingMgr & instance()
Returns a single instance of Multi Threading Manager.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
boost::shared_ptr< TlsContext > TlsContextPtr
The type of shared pointers to TlsContext objects.
boost::shared_ptr< IoServiceThreadPool > IoServiceThreadPoolPtr
Defines a pointer to a thread pool.
boost::shared_ptr< isc::asiolink::IntervalTimer > IntervalTimerPtr
boost::shared_ptr< IOService > IOServicePtr
Defines a smart pointer to an IOService instance.
const isc::log::MessageID HTTP_CLIENT_MT_STARTED
const isc::log::MessageID HTTP_CONNECTION_CLOSE_CALLBACK_FAILED
const isc::log::MessageID HTTP_BAD_SERVER_RESPONSE_RECEIVED
isc::log::Logger http_logger("http")
Defines the logger used within libkea-http library.
const isc::log::MessageID HTTP_SERVER_RESPONSE_RECEIVED
boost::shared_ptr< HttpResponseParser > HttpResponseParserPtr
Pointer to the HttpResponseParser.
const isc::log::MessageID HTTP_CLIENT_REQUEST_SEND
boost::shared_ptr< HttpResponse > HttpResponsePtr
Pointer to the HttpResponse object.
const isc::log::MessageID HTTP_BAD_SERVER_RESPONSE_RECEIVED_DETAILS
const isc::log::MessageID HTTP_CLIENT_REQUEST_SEND_DETAILS
const isc::log::MessageID HTTP_CLIENT_QUEUE_SIZE_GROWING
const isc::log::MessageID HTTP_SERVER_RESPONSE_RECEIVED_DETAILS
boost::shared_ptr< HttpRequest > HttpRequestPtr
Pointer to the HttpRequest object.
const isc::log::MessageID HTTP_PREMATURE_CONNECTION_TIMEOUT_OCCURRED
const int DBGLVL_TRACE_BASIC
Trace basic operations.
const int DBGLVL_TRACE_DETAIL_DATA
Trace data associated with detailed operations.
const int DBGLVL_TRACE_BASIC_DATA
Trace data associated with the basic operations.
const int DBGLVL_TRACE_DETAIL
Trace detailed operations.
std::function< void(boost::system::error_code ec, size_t length)> SocketCallbackFunction
Type of the function implementing a callback invoked by the SocketCallback functor.
Defines the logger used by the top-level component of kea-lfc.
HTTP request/response timeout value.
long value_
Timeout value specified.