Is there an example multi-threaded HTTP client to OpenSSL?

Guys, please share the example multi-threaded HTTP client to OpenSSL.
Interested in:
1. OpenSSL 1.1+ (there changed API for multi-threading)
2. HTTP 1.1 (in particular, Keep-alive)
3. What handle (ctx, ssl, bio) can be stored globally, and what is needed for each thread?
4. What and when you want lochit (CRYPTO_THREAD_write_lock) in thread? Now locu all, maybe you can lochit only moment connect?
5. How to determine that the client has closed the connection and perconnection? Preferably before pissing in it.

The test certificates and so on securely for simplicity, omitted. In the example, each thread will connect to the same host, that are in fact different. Within one thread, of course, the connection and the host is permanent.

Now something like this (for Windows, but only in terms of creating the thread):
CRYPTO_RWLOCK *lock;
SSL_CTX* ctx;
SSL* ssl; // can be static?

static void init() {
SSL_library_init();
SSL_load_error_strings();
ERR_load_BIO_strings();
OpenSSL_add_all_algorithms();
lock = CRYPTO_THREAD_lock_new();
ctx = SSL_CTX_new(TLS_method());
SSL_CTX_set_options(ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
}

static void finish() {
CRYPTO_THREAD_lock_free(lock);
SSL_free(ssl);
SSL_CTX_free(ctx);
}


#define host "example.com"

DWORD WINAPI ThreadProc( LPVOID lpParameter) {
if(CRYPTO_THREAD_write_lock(lock)) { // ctx lock
BIO* bio = BIO_new_ssl_connect(ctx);
BIO_get_ssl(bio, &ssl); // it seems to me that ssl needs to be their for each connect, no?
if (ssl) {
 SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
 BIO_set_conn_hostname(bio, host);
 BIO_set_conn_port(bio, "443");
 SSL_set_tlsext_host_name(ssl, host);
 if (BIO_do_connect(bio) == ) { // connects to the host
 for(int i=0; i<5; ++i) { // for example, consistently send the same 5 queries in one connection
 const char* buffer = "GET / HTTP/1.1\r\nHost: example.com\r\nConnection: keep-alive\r\nAccept: */*\r\n\r\n";
 int r = 0;
 do { // send the request
 r = BIO_write(bio, buffer, strlen(buffer));
 if (r < 0) {
 if (!BIO_should_retry(bio)) {
CRYPTO_THREAD_unlock(lock);
 return EXIT_FAILURE;
}
}
 } while (r > 0 || BIO_should_retry(bio));

 http_parser parser; // parser chunked response

 int r = 0, rall = 0;
 char buffer[4096];
 do { // read response
 r = BIO_read(bio, buffer, sizeof(buffer));
 if (r > 0) {
 rall += parser.Parse(buffer, r);
}
 else if (r < 0) {
 if (!BIO_should_retry(bio))
CRYPTO_THREAD_unlock(lock);
 return EXIT_FAILURE;
}
}
 } while ((r > 0 || BIO_should_retry(bio)) && !parser.IsError() && !parser.IsFinished());
}
}
 CRYPTO_THREAD_unlock(lock); // maybe you can unlock immediately after the connect?
}
 BIO_ssl_shutdown(bio); // close connection
SSL_free(bio);
}
return EXIT_SUCCESS;
}

#define THREADS 10


int main() {
init(); // inicializacia library
for( int i=0; i<THREADS; i++ ) { // create 10 threads
 hThreadArray[i] = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
}
WaitForMultipleObjects(THREADS, hThreadArray, TRUE, INFINITE); // waiting for-with
for(int i=0; i<THREADS; i++) { // close
CloseHandle(hThreadArray[i]);
}
finish(); // free library resources
return EXIT_SUCCESS;
}

Maybe there are some inaccuracies in the code is pseudocode.
PS do you know that can be better using non-blocking I/O, but it is necessary in this architecture to do that.
March 19th 20 at 08:30
1 answer
March 19th 20 at 08:32
M-m-m, what about curl? - lamont.Kilback62 commented on March 19th 20 at 08:35
@lamont.Kilback62, it's just they decided to call the class in the example CURL. In fact they have very advanced all written. Plus, this bonus goes fizz(TLS v1.3) - Myra_Rau commented on March 19th 20 at 08:38

Find more questions by tags C++OpenSSL