tls_session_reuse.c (7898B)
1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 9 * 10 * This software is licensed as described in the file COPYING, which 11 * you should have received as part of this distribution. The terms 12 * are also available at https://curl.se/docs/copyright.html. 13 * 14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 15 * copies of the Software, and permit persons to whom the Software is 16 * furnished to do so, under the terms of the COPYING file. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 * SPDX-License-Identifier: curl 22 * 23 ***************************************************************************/ 24 #include "first.h" 25 26 static int tse_found_tls_session = FALSE; 27 28 static size_t write_tse_cb(char *ptr, size_t size, size_t nmemb, void *opaque) 29 { 30 CURL *easy = opaque; 31 (void)ptr; 32 if(!tse_found_tls_session) { 33 struct curl_tlssessioninfo *tlssession; 34 CURLcode rc; 35 36 rc = curl_easy_getinfo(easy, CURLINFO_TLS_SSL_PTR, &tlssession); 37 if(rc) { 38 curl_mfprintf(stderr, "curl_easy_getinfo(CURLINFO_TLS_SSL_PTR) " 39 "failed: %s\n", curl_easy_strerror(rc)); 40 return rc; 41 } 42 if(tlssession->backend == CURLSSLBACKEND_NONE) { 43 curl_mfprintf(stderr, "curl_easy_getinfo(CURLINFO_TLS_SSL_PTR) " 44 "gave no backend\n"); 45 return CURLE_FAILED_INIT; 46 } 47 if(!tlssession->internals) { 48 curl_mfprintf(stderr, "curl_easy_getinfo(CURLINFO_TLS_SSL_PTR) " 49 "missing\n"); 50 return CURLE_FAILED_INIT; 51 } 52 tse_found_tls_session = TRUE; 53 } 54 return size * nmemb; 55 } 56 57 static CURL *tse_add_transfer(CURLM *multi, CURLSH *share, 58 struct curl_slist *resolve, 59 const char *url, long http_version) 60 { 61 CURL *easy; 62 CURLMcode mc; 63 64 easy = curl_easy_init(); 65 if(!easy) { 66 curl_mfprintf(stderr, "curl_easy_init failed\n"); 67 return NULL; 68 } 69 curl_easy_setopt(easy, CURLOPT_VERBOSE, 1L); 70 curl_easy_setopt(easy, CURLOPT_DEBUGFUNCTION, debug_cb); 71 curl_easy_setopt(easy, CURLOPT_URL, url); 72 curl_easy_setopt(easy, CURLOPT_SHARE, share); 73 curl_easy_setopt(easy, CURLOPT_NOSIGNAL, 1L); 74 curl_easy_setopt(easy, CURLOPT_AUTOREFERER, 1L); 75 curl_easy_setopt(easy, CURLOPT_FAILONERROR, 1L); 76 curl_easy_setopt(easy, CURLOPT_HTTP_VERSION, http_version); 77 curl_easy_setopt(easy, CURLOPT_WRITEFUNCTION, write_tse_cb); 78 curl_easy_setopt(easy, CURLOPT_WRITEDATA, easy); 79 curl_easy_setopt(easy, CURLOPT_HTTPGET, 1L); 80 curl_easy_setopt(easy, CURLOPT_SSL_VERIFYPEER, 0L); 81 if(resolve) 82 curl_easy_setopt(easy, CURLOPT_RESOLVE, resolve); 83 84 85 mc = curl_multi_add_handle(multi, easy); 86 if(mc != CURLM_OK) { 87 curl_mfprintf(stderr, "curl_multi_add_handle: %s\n", 88 curl_multi_strerror(mc)); 89 curl_easy_cleanup(easy); 90 return NULL; 91 } 92 return easy; 93 } 94 95 static int test_tls_session_reuse(int argc, char *argv[]) 96 { 97 const char *url; 98 CURLM *multi = NULL; 99 CURLMcode mc; 100 int running_handles = 0, numfds; 101 CURLMsg *msg; 102 CURLSH *share = NULL; 103 CURLU *cu; 104 struct curl_slist *resolve = NULL; 105 char resolve_buf[1024]; 106 int msgs_in_queue; 107 int add_more, waits, ongoing = 0; 108 char *host = NULL, *port = NULL; 109 int http_version = CURL_HTTP_VERSION_1_1; 110 int exitcode = 1; 111 112 if(argc != 3) { 113 curl_mfprintf(stderr, "%s proto URL\n", argv[0]); 114 return 2; 115 } 116 117 if(!strcmp("h2", argv[1])) 118 http_version = CURL_HTTP_VERSION_2; 119 else if(!strcmp("h3", argv[1])) 120 http_version = CURL_HTTP_VERSION_3ONLY; 121 122 url = argv[2]; 123 cu = curl_url(); 124 if(!cu) { 125 curl_mfprintf(stderr, "out of memory\n"); 126 return 1; 127 } 128 if(curl_url_set(cu, CURLUPART_URL, url, 0)) { 129 curl_mfprintf(stderr, "not a URL: '%s'\n", url); 130 goto cleanup; 131 } 132 if(curl_url_get(cu, CURLUPART_HOST, &host, 0)) { 133 curl_mfprintf(stderr, "could not get host of '%s'\n", url); 134 goto cleanup; 135 } 136 if(curl_url_get(cu, CURLUPART_PORT, &port, 0)) { 137 curl_mfprintf(stderr, "could not get port of '%s'\n", url); 138 goto cleanup; 139 } 140 141 curl_msnprintf(resolve_buf, sizeof(resolve_buf)-1, "%s:%s:127.0.0.1", 142 host, port); 143 resolve = curl_slist_append(resolve, resolve_buf); 144 145 multi = curl_multi_init(); 146 if(!multi) { 147 curl_mfprintf(stderr, "curl_multi_init failed\n"); 148 goto cleanup; 149 } 150 151 share = curl_share_init(); 152 if(!share) { 153 curl_mfprintf(stderr, "curl_share_init failed\n"); 154 goto cleanup; 155 } 156 curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION); 157 158 159 if(!tse_add_transfer(multi, share, resolve, url, http_version)) 160 goto cleanup; 161 ++ongoing; 162 add_more = 6; 163 waits = 3; 164 do { 165 mc = curl_multi_perform(multi, &running_handles); 166 if(mc != CURLM_OK) { 167 curl_mfprintf(stderr, "curl_multi_perform: %s\n", 168 curl_multi_strerror(mc)); 169 goto cleanup; 170 } 171 172 if(running_handles) { 173 mc = curl_multi_poll(multi, NULL, 0, 1000000, &numfds); 174 if(mc != CURLM_OK) { 175 curl_mfprintf(stderr, "curl_multi_poll: %s\n", 176 curl_multi_strerror(mc)); 177 goto cleanup; 178 } 179 } 180 181 if(waits) { 182 --waits; 183 } 184 else { 185 while(add_more) { 186 if(!tse_add_transfer(multi, share, resolve, url, http_version)) 187 goto cleanup; 188 ++ongoing; 189 --add_more; 190 } 191 } 192 193 /* Check for finished handles and remove. */ 194 /* !checksrc! disable EQUALSNULL 1 */ 195 while((msg = curl_multi_info_read(multi, &msgs_in_queue)) != NULL) { 196 if(msg->msg == CURLMSG_DONE) { 197 long status = 0; 198 curl_off_t xfer_id; 199 curl_easy_getinfo(msg->easy_handle, CURLINFO_XFER_ID, &xfer_id); 200 curl_easy_getinfo(msg->easy_handle, CURLINFO_RESPONSE_CODE, &status); 201 if(msg->data.result == CURLE_SEND_ERROR || 202 msg->data.result == CURLE_RECV_ERROR) { 203 /* We get these if the server had a GOAWAY in transit on 204 * re-using a connection */ 205 } 206 else if(msg->data.result) { 207 curl_mfprintf(stderr, "transfer #%" CURL_FORMAT_CURL_OFF_T 208 ": failed with %d\n", xfer_id, msg->data.result); 209 goto cleanup; 210 } 211 else if(status != 200) { 212 curl_mfprintf(stderr, "transfer #%" CURL_FORMAT_CURL_OFF_T 213 ": wrong http status %ld (expected 200)\n", xfer_id, 214 status); 215 goto cleanup; 216 } 217 curl_multi_remove_handle(multi, msg->easy_handle); 218 curl_easy_cleanup(msg->easy_handle); 219 --ongoing; 220 curl_mfprintf(stderr, "transfer #%" CURL_FORMAT_CURL_OFF_T" retiring " 221 "(%d now running)\n", xfer_id, running_handles); 222 } 223 } 224 225 curl_mfprintf(stderr, "running_handles=%d, yet_to_start=%d\n", 226 running_handles, add_more); 227 228 } while(ongoing || add_more); 229 230 if(!tse_found_tls_session) { 231 curl_mfprintf(stderr, "CURLINFO_TLS_SSL_PTR not found during run\n"); 232 exitcode = CURLE_FAILED_INIT; 233 goto cleanup; 234 } 235 236 curl_mfprintf(stderr, "exiting\n"); 237 exitcode = 0; 238 239 cleanup: 240 241 if(multi) { 242 CURL **list = curl_multi_get_handles(multi); 243 if(list) { 244 int i; 245 for(i = 0; list[i]; i++) { 246 curl_multi_remove_handle(multi, list[i]); 247 curl_easy_cleanup(list[i]); 248 } 249 curl_free(list); 250 } 251 curl_multi_cleanup(multi); 252 } 253 curl_share_cleanup(share); 254 curl_slist_free_all(resolve); 255 curl_free(host); 256 curl_free(port); 257 curl_url_cleanup(cu); 258 259 return exitcode; 260 }