bearssl: handshake fix, provide proper get_select_socks() implementation

- bring bearssl handshake times down from +200ms down to other TLS backends
- vtls: improve generic get_select_socks() implementation
- tests: provide Apache with a suitable ssl session cache

Closes #11675
diff --git a/lib/vtls/bearssl.c b/lib/vtls/bearssl.c
index 2fbbde6..9ab55dc 100644
--- a/lib/vtls/bearssl.c
+++ b/lib/vtls/bearssl.c
@@ -587,6 +587,7 @@
   const bool verifyhost = conn_config->verifyhost;
   CURLcode ret;
   unsigned version_min, version_max;
+  int session_set = 0;
 #ifdef ENABLE_IPV6
   struct in6_addr addr;
 #else
@@ -594,6 +595,7 @@
 #endif
 
   DEBUGASSERT(backend);
+  CURL_TRC_CF(data, cf, "connect_step1");
 
   switch(conn_config->version) {
   case CURL_SSLVERSION_SSLv2:
@@ -631,6 +633,7 @@
       source.data = ca_info_blob->data;
       source.len = ca_info_blob->len;
 
+      CURL_TRC_CF(data, cf, "connect_step1, load ca_info_blob");
       ret = load_cafile(&source, &backend->anchors, &backend->anchors_len);
       if(ret != CURLE_OK) {
         failf(data, "error importing CA certificate blob");
@@ -644,6 +647,7 @@
       source.data = ssl_cafile;
       source.len = 0;
 
+      CURL_TRC_CF(data, cf, "connect_step1, load cafile");
       ret = load_cafile(&source, &backend->anchors, &backend->anchors_len);
       if(ret != CURLE_OK) {
         failf(data, "error setting certificate verify locations."
@@ -663,6 +667,7 @@
   if(conn_config->cipher_list) {
     /* Override the ciphers as specified. For the default cipher list see the
        BearSSL source code of br_ssl_client_init_full() */
+    CURL_TRC_CF(data, cf, "connect_step1, set ciphers");
     ret = bearssl_set_selected_ciphers(data, &backend->ctx.eng,
                                        conn_config->cipher_list);
     if(ret)
@@ -678,9 +683,11 @@
   if(ssl_config->primary.sessionid) {
     void *session;
 
+    CURL_TRC_CF(data, cf, "connect_step1, check session cache");
     Curl_ssl_sessionid_lock(data);
     if(!Curl_ssl_getsessionid(cf, data, &session, NULL)) {
       br_ssl_engine_set_session_parameters(&backend->ctx.eng, session);
+      session_set = 1;
       infof(data, "BearSSL: re-using session ID");
     }
     Curl_ssl_sessionid_unlock(data);
@@ -718,6 +725,7 @@
       return CURLE_SSL_CONNECT_ERROR;
     }
     hostname = snihost;
+    CURL_TRC_CF(data, cf, "connect_step1, SNI set");
   }
 
   /* give application a chance to interfere with SSL set up. */
@@ -732,7 +740,7 @@
     }
   }
 
-  if(!br_ssl_client_reset(&backend->ctx, hostname, 1))
+  if(!br_ssl_client_reset(&backend->ctx, hostname, session_set))
     return CURLE_FAILED_INIT;
   backend->active = TRUE;
 
@@ -741,6 +749,28 @@
   return CURLE_OK;
 }
 
+static int bearssl_get_select_socks(struct Curl_cfilter *cf,
+                                    struct Curl_easy *data,
+                                    curl_socket_t *socks)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  curl_socket_t sock = Curl_conn_cf_get_socket(cf->next, data);
+
+  if(sock == CURL_SOCKET_BAD)
+    return GETSOCK_BLANK;
+  else {
+    struct bearssl_ssl_backend_data *backend =
+      (struct bearssl_ssl_backend_data *)connssl->backend;
+    unsigned state = br_ssl_engine_current_state(&backend->ctx.eng);
+    if(state & BR_SSL_SENDREC) {
+      socks[0] = sock;
+      return GETSOCK_WRITESOCK(0);
+    }
+  }
+  socks[0] = sock;
+  return GETSOCK_READSOCK(0);
+}
+
 static CURLcode bearssl_run_until(struct Curl_cfilter *cf,
                                   struct Curl_easy *data,
                                   unsigned target)
@@ -792,6 +822,7 @@
     if(state & BR_SSL_SENDREC) {
       buf = br_ssl_engine_sendrec_buf(&backend->ctx.eng, &len);
       ret = Curl_conn_cf_send(cf->next, data, (char *)buf, len, &result);
+      CURL_TRC_CF(data, cf, "ssl_send(len=%zu) -> %zd, %d", len, ret, result);
       if(ret <= 0) {
         return result;
       }
@@ -800,6 +831,7 @@
     else if(state & BR_SSL_RECVREC) {
       buf = br_ssl_engine_recvrec_buf(&backend->ctx.eng, &len);
       ret = Curl_conn_cf_recv(cf->next, data, (char *)buf, len, &result);
+      CURL_TRC_CF(data, cf, "ssl_recv(len=%zu) -> %zd, %d", len, ret, result);
       if(ret == 0) {
         failf(data, "SSL: EOF without close notify");
         return CURLE_READ_ERROR;
@@ -821,16 +853,26 @@
   CURLcode ret;
 
   DEBUGASSERT(backend);
+  CURL_TRC_CF(data, cf, "connect_step2");
 
   ret = bearssl_run_until(cf, data, BR_SSL_SENDAPP | BR_SSL_RECVAPP);
   if(ret == CURLE_AGAIN)
     return CURLE_OK;
   if(ret == CURLE_OK) {
+    unsigned int tver;
     if(br_ssl_engine_current_state(&backend->ctx.eng) == BR_SSL_CLOSED) {
       failf(data, "SSL: connection closed during handshake");
       return CURLE_SSL_CONNECT_ERROR;
     }
     connssl->connecting_state = ssl_connect_3;
+    /* Informational message */
+    tver = br_ssl_engine_get_version(&backend->ctx.eng);
+    if(tver == 0x0303)
+      infof(data, "SSL connection using TLSv1.2");
+    else if(tver == 0x0304)
+      infof(data, "SSL connection using TLSv1.3");
+    else
+      infof(data, "SSL connection using TLS 0x%x", tver);
   }
   return ret;
 }
@@ -846,6 +888,7 @@
 
   DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
   DEBUGASSERT(backend);
+  CURL_TRC_CF(data, cf, "connect_step3");
 
   if(connssl->alpn) {
     const char *proto;
@@ -954,8 +997,10 @@
   timediff_t timeout_ms;
   int what;
 
+  CURL_TRC_CF(data, cf, "connect_common(blocking=%d)", !nonblocking);
   /* check if the connection has already been established */
   if(ssl_connection_complete == connssl->state) {
+    CURL_TRC_CF(data, cf, "connect_common, connected");
     *done = TRUE;
     return CURLE_OK;
   }
@@ -987,8 +1032,10 @@
       curl_socket_t readfd = ssl_connect_2_reading ==
         connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
 
+      CURL_TRC_CF(data, cf, "connect_common, check socket");
       what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
                                nonblocking?0:timeout_ms);
+      CURL_TRC_CF(data, cf, "connect_common, check socket -> %d", what);
       if(what < 0) {
         /* fatal error */
         failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
@@ -1163,7 +1210,7 @@
   Curl_none_cert_status_request,   /* cert_status_request */
   bearssl_connect,                 /* connect */
   bearssl_connect_nonblocking,     /* connect_nonblocking */
-  Curl_ssl_get_select_socks,                /* getsock */
+  bearssl_get_select_socks,        /* getsock */
   bearssl_get_internals,           /* get_internals */
   bearssl_close,                   /* close_one */
   Curl_none_close_all,             /* close_all */
diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c
index 2dbf27b..68caadd 100644
--- a/lib/vtls/vtls.c
+++ b/lib/vtls/vtls.c
@@ -635,19 +635,16 @@
   struct ssl_connect_data *connssl = cf->ctx;
   curl_socket_t sock = Curl_conn_cf_get_socket(cf->next, data);
 
-  if(sock != CURL_SOCKET_BAD) {
-    if(connssl->connecting_state == ssl_connect_2_writing) {
-      /* write mode */
-      socks[0] = sock;
-      return GETSOCK_WRITESOCK(0);
-    }
-    if(connssl->connecting_state == ssl_connect_2_reading) {
-      /* read mode */
-      socks[0] = sock;
-      return GETSOCK_READSOCK(0);
-    }
+  if(sock == CURL_SOCKET_BAD)
+    return GETSOCK_BLANK;
+
+  if(connssl->connecting_state == ssl_connect_2_writing) {
+    /* we are only interested in writing */
+    socks[0] = sock;
+    return GETSOCK_WRITESOCK(0);
   }
-  return GETSOCK_BLANK;
+  socks[0] = sock;
+  return GETSOCK_READSOCK(0);
 }
 
 /* Selects an SSL crypto engine
@@ -1512,6 +1509,7 @@
   }
 
   CF_DATA_SAVE(save, cf, data);
+  CURL_TRC_CF(data, cf, "cf_connect()");
   (void)connssl;
   DEBUGASSERT(data->conn);
   DEBUGASSERT(data->conn == cf->conn);
@@ -1541,6 +1539,7 @@
     DEBUGASSERT(connssl->state == ssl_connection_complete);
   }
 out:
+  CURL_TRC_CF(data, cf, "cf_connect() -> %d, done=%d", result, *done);
   CF_DATA_RESTORE(cf, save);
   return result;
 }
@@ -1601,12 +1600,17 @@
                                    curl_socket_t *socks)
 {
   struct cf_call_data save;
-  int result;
+  int fds = GETSOCK_BLANK;
 
-  CF_DATA_SAVE(save, cf, data);
-  result = Curl_ssl->get_select_socks(cf, data, socks);
-  CF_DATA_RESTORE(cf, save);
-  return result;
+  if(!cf->next->connected) {
+    fds = cf->next->cft->get_select_socks(cf->next, data, socks);
+  }
+  else if(!cf->connected) {
+    CF_DATA_SAVE(save, cf, data);
+    fds = Curl_ssl->get_select_socks(cf, data, socks);
+    CF_DATA_RESTORE(cf, save);
+  }
+  return fds;
 }
 
 static CURLcode ssl_cf_cntrl(struct Curl_cfilter *cf,
diff --git a/tests/http/testenv/httpd.py b/tests/http/testenv/httpd.py
index ecc7c6c..38a8a8b 100644
--- a/tests/http/testenv/httpd.py
+++ b/tests/http/testenv/httpd.py
@@ -48,6 +48,7 @@
         'authz_user', 'authz_core', 'authz_host',
         'auth_basic', 'auth_digest',
         'env', 'filter', 'headers', 'mime',
+        'socache_shmcb',
         'rewrite', 'http2', 'ssl', 'proxy', 'proxy_http', 'proxy_connect',
         'mpm_event',
     ]
@@ -251,6 +252,7 @@
                 f'Listen {self.env.proxy_port}',
                 f'Listen {self.env.proxys_port}',
                 f'TypesConfig "{self._conf_dir}/mime.types',
+                f'SSLSessionCache "shmcb:ssl_gcache_data(32000)"',
             ]
             if 'base' in self._extra_configs:
                 conf.extend(self._extra_configs['base'])