From d9416c25662168da329d1a34ab1a008eec69ea20 Mon Sep 17 00:00:00 2001 From: eidheim Date: Tue, 4 Jul 2017 23:07:08 +0200 Subject: [PATCH] Added Client::close, and Client::connections and Client::connections_mutex are no longer shared_ptrs --- client_http.hpp | 44 +++++++++++++++++++++++++------------------- server_http.hpp | 6 ++---- server_https.hpp | 4 ---- tests/io_test.cpp | 30 +++++++++++++++--------------- 4 files changed, 42 insertions(+), 42 deletions(-) diff --git a/client_http.hpp b/client_http.hpp index cfd2290..a14c2c8 100644 --- a/client_http.hpp +++ b/client_http.hpp @@ -214,25 +214,24 @@ namespace SimpleWeb { void request(const std::string &method, const std::string &path, string_view content, const CaseInsensitiveMultimap &header, std::function, const error_code &)> &&request_callback_) { auto session = std::make_shared(this->shared_from_this(), get_connection(), create_request_header(method, path, header)); + auto client = session->client; auto connection = session->connection; auto response = session->response; auto request_callback = std::make_shared, const error_code &)>>(std::move(request_callback_)); - auto connections = this->connections; - auto connections_mutex = this->connections_mutex; - session->callback = [connection, response, request_callback, connections, connections_mutex](const error_code &ec) { + session->callback = [client, connection, response, request_callback](const error_code &ec) { { - std::lock_guard lock(*connections_mutex); + std::lock_guard lock(client->connections_mutex); connection->in_use = false; // Remove unused connections, but keep one open for HTTP persistent connection: size_t unused_connections = 0; - for(auto it = connections->begin(); it != connections->end();) { + for(auto it = client->connections.begin(); it != client->connections.end();) { if((*it)->in_use) ++it; else { ++unused_connections; if(unused_connections > 1) - it = connections->erase(it); + it = client->connections.erase(it); else ++it; } @@ -273,25 +272,24 @@ namespace SimpleWeb { void request(const std::string &method, const std::string &path, std::istream &content, const CaseInsensitiveMultimap &header, std::function, const error_code &)> &&request_callback_) { auto session = std::make_shared(this->shared_from_this(), get_connection(), create_request_header(method, path, header)); + auto client = session->client; auto connection = session->connection; auto response = session->response; auto request_callback = std::make_shared, const error_code &)>>(std::move(request_callback_)); - auto connections = this->connections; - auto connections_mutex = this->connections_mutex; - session->callback = [connection, response, request_callback, connections, connections_mutex](const error_code &ec) { + session->callback = [client, connection, response, request_callback](const error_code &ec) { { - std::lock_guard lock(*connections_mutex); + std::lock_guard lock(client->connections_mutex); connection->in_use = false; // Remove unused connections, but keep one open for HTTP persistent connection: size_t unused_connections = 0; - for(auto it = connections->begin(); it != connections->end();) { + for(auto it = client->connections.begin(); it != client->connections.end();) { if((*it)->in_use) ++it; else { ++unused_connections; if(unused_connections > 1) - it = connections->erase(it); + it = client->connections.erase(it); else ++it; } @@ -321,17 +319,25 @@ namespace SimpleWeb { request(method, path, content, CaseInsensitiveMultimap(), std::move(request_callback)); } + /// Close connections + void close() { + std::lock_guard lock(connections_mutex); + for(auto it = connections.begin(); it != connections.end();) { + (*it)->close(); + it = connections.erase(it); + } + } + protected: std::string host; unsigned short port; std::unique_ptr query; - std::shared_ptr>> connections; - std::shared_ptr connections_mutex; + std::vector> connections; + std::mutex connections_mutex; - ClientBase(const std::string &host_port, unsigned short default_port) - : io_service(new asio::io_service()), connections(new std::vector>()), connections_mutex(new std::mutex()) { + ClientBase(const std::string &host_port, unsigned short default_port) : io_service(new asio::io_service()) { auto parsed_host_port = parse_host_port(host_port, default_port); host = parsed_host_port.first; port = parsed_host_port.second; @@ -339,8 +345,8 @@ namespace SimpleWeb { std::shared_ptr get_connection() { std::shared_ptr connection; - std::lock_guard lock(*connections_mutex); - for(auto it = connections->begin(); it != connections->end(); ++it) { + std::lock_guard lock(connections_mutex); + for(auto it = connections.begin(); it != connections.end(); ++it) { if(!(*it)->in_use && !connection) { connection = *it; break; @@ -348,7 +354,7 @@ namespace SimpleWeb { } if(!connection) { connection = create_connection(); - connections->emplace_back(connection); + connections.emplace_back(connection); } connection->reconnecting = false; connection->in_use = true; diff --git a/server_http.hpp b/server_http.hpp index 7d8c27e..6d51186 100644 --- a/server_http.hpp +++ b/server_http.hpp @@ -517,7 +517,7 @@ namespace SimpleWeb { return; } } - }; // namespace SimpleWeb + }; template class Server : public ServerBase {}; @@ -538,12 +538,10 @@ namespace SimpleWeb { Server() : ServerBase::ServerBase(80) {} void accept() override { - //Create new socket for this connection - //Shared_ptr is used to pass temporary objects to the asynchronous functions auto session = std::make_shared(this->shared_from_this(), std::make_shared(*io_service)); acceptor->async_accept(*session->socket, [this, session](const error_code &ec) { - //Immediately start accepting a new connection (if io_service hasn't been stopped) + //Immediately start accepting a new connection (unless io_service has been stopped) if(ec != asio::error::operation_aborted) this->accept(); diff --git a/server_https.hpp b/server_https.hpp index 83abfce..3ab1796 100644 --- a/server_https.hpp +++ b/server_https.hpp @@ -55,16 +55,12 @@ namespace SimpleWeb { asio::ssl::context context; void accept() override { - //Create new socket for this connection - //Shared_ptr is used to pass temporary objects to the asynchronous functions auto session = std::make_shared(this->shared_from_this(), std::make_shared(*io_service, context)); acceptor->async_accept(session->socket->lowest_layer(), [this, session](const error_code &ec) { - //Immediately start accepting a new connection (if io_service hasn't been stopped) if(ec != asio::error::operation_aborted) this->accept(); - if(!ec) { asio::ip::tcp::no_delay option(true); session->socket->lowest_layer().set_option(option); diff --git a/tests/io_test.cpp b/tests/io_test.cpp index b827924..9d47c5f 100644 --- a/tests/io_test.cpp +++ b/tests/io_test.cpp @@ -151,8 +151,8 @@ int main() { auto r = client->request("POST", "/string", content); output << r->content.rdbuf(); assert(output.str() == "A string"); - assert(client->connections->size() == 1); - connection = client->connections->front().get(); + assert(client->connections.size() == 1); + connection = client->connections.front().get(); } { @@ -160,8 +160,8 @@ int main() { auto r = client->request("POST", "/string", "A string"); output << r->content.rdbuf(); assert(output.str() == "A string"); - assert(client->connections->size() == 1); - assert(connection == client->connections->front().get()); + assert(client->connections.size() == 1); + assert(connection == client->connections.front().get()); } { @@ -169,16 +169,16 @@ int main() { auto r = client->request("GET", "/header", "", {{"test1", "test"}, {"test2", "ing"}}); output << r->content.rdbuf(); assert(output.str() == "testing"); - assert(client->connections->size() == 1); - assert(connection == client->connections->front().get()); + assert(client->connections.size() == 1); + assert(connection == client->connections.front().get()); } { stringstream output; auto r = client->request("GET", "/query_string?testing"); assert(r->content.string() == "testing"); - assert(client->connections->size() == 1); - assert(connection == client->connections->front().get()); + assert(client->connections.size() == 1); + assert(connection == client->connections.front().get()); } } @@ -212,10 +212,10 @@ int main() { } for(auto &thread : threads) thread.join(); - assert(client->connections->size() == 100); + assert(client->connections.size() == 100); client->io_service->reset(); client->io_service->run(); - assert(client->connections->size() == 1); + assert(client->connections.size() == 1); for(auto call : calls) assert(call); } @@ -223,18 +223,18 @@ int main() { { auto client = HttpClient::create("localhost:8080"); - assert(client->connections->size() == 0); + assert(client->connections.size() == 0); for(size_t c = 0; c < 5000; ++c) { auto r1 = client->request("POST", "/string", "A string"); assert(SimpleWeb::status_code(r1->status_code) == SimpleWeb::StatusCode::success_ok); assert(r1->content.string() == "A string"); - assert(client->connections->size() == 1); + assert(client->connections.size() == 1); stringstream content("A string"); auto r2 = client->request("POST", "/string", content); assert(SimpleWeb::status_code(r2->status_code) == SimpleWeb::StatusCode::success_ok); assert(r2->content.string() == "A string"); - assert(client->connections->size() == 1); + assert(client->connections.size() == 1); } } @@ -244,7 +244,7 @@ int main() { auto r = client->request("POST", "/string", "A string"); assert(SimpleWeb::status_code(r->status_code) == SimpleWeb::StatusCode::success_ok); assert(r->content.string() == "A string"); - assert(client->connections->size() == 1); + assert(client->connections.size() == 1); } { @@ -253,7 +253,7 @@ int main() { auto r = client->request("POST", "/string", content); assert(SimpleWeb::status_code(r->status_code) == SimpleWeb::StatusCode::success_ok); assert(r->content.string() == "A string"); - assert(client->connections->size() == 1); + assert(client->connections.size() == 1); } }