Skip to content

Instantly share code, notes, and snippets.

@kzemek
Created August 13, 2015 17:19
Show Gist options
  • Save kzemek/9f7a8d94171197a9f88e to your computer and use it in GitHub Desktop.
Save kzemek/9f7a8d94171197a9f88e to your computer and use it in GitHub Desktop.
#include <asio.hpp>
#include <asio/ssl.hpp>
#include <algorithm>
#include <atomic>
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <memory>
#include <thread>
#include <vector>
class ServerConnection {
public:
ServerConnection(asio::io_service &ioService, asio::ssl::context &context,
std::size_t messageSize)
: m_socket{ioService, context}
, m_buffer(messageSize)
{
++s_runningConnections;
}
~ServerConnection() { --s_runningConnections; }
asio::ssl::stream<asio::ip::tcp::socket>::lowest_layer_type &socket()
{
return m_socket.lowest_layer();
}
void start(std::shared_ptr<ServerConnection> self, std::size_t messages)
{
m_socket.async_handshake(asio::ssl::stream_base::server,
[=](const asio::error_code &) { asyncRead(self, messages); });
}
static std::size_t runningConnections() { return s_runningConnections; }
private:
void asyncRead(std::shared_ptr<ServerConnection> self, std::size_t messages)
{
asio::async_read(m_socket, asio::buffer(m_buffer),
[=](const asio::error_code &, std::size_t) {
if (messages > 1)
asyncRead(self, messages - 1);
});
}
static std::atomic<std::size_t> s_runningConnections;
asio::ssl::stream<asio::ip::tcp::socket> m_socket;
std::vector<char> m_buffer;
};
std::atomic<std::size_t> ServerConnection::s_runningConnections{0};
class Server {
public:
Server(asio::io_service &ioService, std::size_t connections,
std::size_t messages, std::size_t messageSize)
: m_ioService{ioService}
, m_messages{messages}
, m_messageSize{messageSize}
{
m_context.use_certificate_chain_file("server.pem");
m_context.use_private_key_file("server.key", asio::ssl::context::pem);
asyncAccept(connections);
}
private:
void asyncAccept(std::size_t connections)
{
auto conn = std::make_shared<ServerConnection>(
m_ioService, m_context, m_messageSize);
m_acceptor.async_accept(conn->socket(), [=](const asio::error_code &) {
conn->start(conn, m_messages);
if (connections > 1)
asyncAccept(connections - 1);
});
}
asio::io_service &m_ioService;
std::size_t m_messages;
std::size_t m_messageSize;
asio::ssl::context m_context{asio::ssl::context::tlsv12_server};
asio::ip::tcp::acceptor m_acceptor{
m_ioService, {asio::ip::tcp::v4(), 5555}};
};
class ClientConnection {
public:
ClientConnection(asio::io_service &ioService,
asio::ip::tcp::resolver::iterator iterator, std::size_t messageSize)
: m_socket{ioService, m_context}
, m_buffer(messageSize)
{
asio::connect(m_socket.lowest_layer(), iterator);
m_socket.handshake(asio::ssl::stream_base::client);
}
void asyncSend(std::size_t messages)
{
asio::async_write(m_socket, asio::buffer(m_buffer),
[=](const asio::error_code &, std::size_t) {
if (messages > 1)
asyncSend(messages - 1);
});
}
private:
asio::ssl::context m_context{asio::ssl::context::tlsv12_client};
asio::ssl::stream<asio::ip::tcp::socket> m_socket;
std::vector<char> m_buffer;
};
std::vector<std::thread> createThreads(
asio::io_service &ioService, std::size_t number)
{
std::vector<std::thread> threads;
std::generate_n(std::back_inserter(threads), number,
[&] { return std::thread{[&] { ioService.run(); }}; });
return threads;
}
std::vector<std::shared_ptr<ClientConnection>> createClients(
asio::io_service &ioService, std::size_t messageSize, std::size_t number)
{
asio::ip::tcp::resolver resolver{ioService};
auto iterator = resolver.resolve({"127.0.0.1", "5555"});
std::vector<std::shared_ptr<ClientConnection>> clients;
std::generate_n(std::back_inserter(clients), number, [&] {
return std::make_shared<ClientConnection>(
ioService, iterator, messageSize);
});
return clients;
}
std::chrono::milliseconds measureTransferTime(
std::vector<std::shared_ptr<ClientConnection>> &clients,
std::size_t messages)
{
auto startTime = std::chrono::steady_clock::now();
for (auto &client : clients)
client->asyncSend(messages);
while (ServerConnection::runningConnections() != 0)
std::this_thread::sleep_for(std::chrono::milliseconds{10});
auto stopTime = std::chrono::steady_clock::now();
return std::chrono::duration_cast<std::chrono::milliseconds>(
stopTime - startTime);
}
int main(int argc, char *argv[])
{
if (argc < 5) {
std::cout << "Usage: " << argv[0]
<< " threads connections messages messageSize" << std::endl;
return 1;
}
std::size_t threadsNo = std::atoll(argv[1]);
std::size_t connections = std::atoll(argv[2]);
std::size_t messages = std::atoll(argv[3]);
std::size_t messageSize = std::atoll(argv[4]);
asio::io_service ioService;
asio::io_service::work idleWork{ioService};
auto threads = createThreads(ioService, threadsNo);
Server server{ioService, connections, messages, messageSize};
auto clients = createClients(ioService, messageSize, connections);
auto duration = measureTransferTime(clients, messages);
auto seconds = static_cast<double>(duration.count()) / 1000;
auto megabytes =
static_cast<double>(connections * messages * messageSize) / 1024 / 1024;
std::cout << megabytes << " megabytes sent and received in " << seconds
<< " seconds. (" << (megabytes / seconds) << " MB/s)"
<< std::endl;
ioService.stop();
for (auto &thread : threads)
thread.join();
return 0;
}
-----BEGIN PRIVATE KEY-----
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAL3LACAeyeApIr3L
n88mv087ycqLG/DmAWC6I0fp1HD3ltC6IuAHHhp4WJhrfgJmXJJeAGZdg+X6GpCa
LAWngWLBOg6NvMdfOiKOOQhF88M9vwfmeOgCfsOjNFUtmwOe1N+r4eqKdQuVNdHg
k0ONsb8m8Mq1fz77hetRG/9YGEhrAgMBAAECgYEAirVHNTJrRgmqW13rQQFHhkfi
9cVvOUNQNHo1eMRbP+ijb47qGCL7jEryLQs6f9SByXMsBaRI1pZQPeh/Te6a7uet
TPpqlN/Z9j5W7OxYOb90jpqlRU9nHYlmEMVO4KvlRaevWz735ST17xCWuH4WbVX5
dmElt1ybTjjPdEslndECQQDuWZKjx4FSVc2m8R9fGquQJI2LYgH0/U5vyVzh3MkT
bx5N+SbOGnsafAl628mLVp/221qhKq/IR7NyVG7WezdpAkEAy9jtpx5MfRBs/wbm
SAbDaeePdL1lEt/8fxYarq1ga0PL/3SxH5hl1YBdC09+N3JAenwGKIBG8okJI9dq
prT6swJAXGqovA5IK2ePlNJbaqHJsdsqcsfuoFJzTk7ST9UutfVY17zqefG0l8FO
X6/GxtswrSPCUUle3RZIEuWAEHO4OQJAVWWAUdV4l6AM+V2rlRr4PGKcj3xUXm7l
OVxKO0k4rlcNm+wH08OlTabj07wulQ3RAz732Xm7vxk3cgNpk4MXzwJBALHeBfTR
EqYLdHIDKhBrm2EuFFAoQIxJbfZCb/u3ozSJWoBgYo5VebJArXqojlvCu0nxXKb6
n826OagnAPUcYn4=
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIICsTCCAhqgAwIBAgIJAJThyYbbS2KwMA0GCSqGSIb3DQEBCwUAMFMxCzAJBgNV
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
aWRnaXRzIFB0eSBMdGQxDDAKBgNVBAMMA29tZzAeFw0xNTA0MjYxMjA2MTRaFw0x
NTA1MjYxMjA2MTRaMFMxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRl
MSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDDAKBgNVBAMMA29t
ZzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAvcsAIB7J4Ckivcufzya/TzvJ
yosb8OYBYLojR+nUcPeW0Loi4AceGnhYmGt+AmZckl4AZl2D5foakJosBaeBYsE6
Do28x186Io45CEXzwz2/B+Z46AJ+w6M0VS2bA57U36vh6op1C5U10eCTQ42xvybw
yrV/PvuF61Eb/1gYSGsCAwEAAaOBjDCBiTA5BgNVHR8EMjAwMC6gLKAqhihodHRw
Oi8vc3R1ZGVudC5hZ2guZWR1LnBsL356ZW1lay9jcmwucGVtMB0GA1UdDgQWBBQD
w/MdQampMXELP0eFTHq8HR9TmzAfBgNVHSMEGDAWgBQDw/MdQampMXELP0eFTHq8
HR9TmzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4GBAG/G0wF8eqBicaS5
8/pyPVcdQXwl89QF84zayGKQs3KynrORiDDH1WHQOzY4C2PzAX4KoOm/tNJ+K10v
QWyFMS+ZeHZEwuwbK4AVlt2qMabze1OrW+7KFZnpyWAQd2GXVIMvjlYgZtfTWFIG
UF0yj8RNyI2GTIthCrqzHgRXYFvA
-----END CERTIFICATE-----
@chronoxor
Copy link

The above problem reproduced only for OpenSSL 1.1.0f build for Windows taken from https://www.npcglib.org/~stathis/blog/precompiled-openssl/

After building the latest stable OpenSSL 1.1.0g everything works without any errors!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment