lib753.c (5229B)
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 #include "testtrace.h" 27 #include "memdebug.h" 28 29 struct t753_transfer_status { 30 CURL *easy; 31 const char *name; 32 bool pause; 33 bool is_paused; 34 bool seen_welcome; 35 }; 36 37 static size_t t753_write_cb(char *ptr, size_t size, size_t nmemb, void *userp) 38 { 39 struct t753_transfer_status *st = userp; 40 size_t len = size * nmemb; 41 (void)ptr; 42 if(st->pause) { 43 curl_mfprintf(stderr, "[%s] write_cb(len=%zu), PAUSE\n", st->name, len); 44 st->is_paused = TRUE; 45 return CURL_READFUNC_PAUSE; 46 } 47 curl_mfprintf(stderr, "[%s] write_cb(len=%zu), CONSUME\n", st->name, len); 48 st->is_paused = FALSE; 49 return len; 50 } 51 52 static size_t t753_hd_cb(char *ptr, size_t size, size_t nmemb, void *userp) 53 { 54 struct t753_transfer_status *st = userp; 55 size_t len = size * nmemb; 56 curl_mfprintf(stderr, "[%s] hd_cb '%.*s'\n", st->name, (int)len, ptr); 57 if(!strcmp("230 Welcome you silly person\r\n", ptr)) { 58 st->seen_welcome = TRUE; 59 st->easy = NULL; 60 } 61 return len; 62 } 63 64 static bool t753_setup(char *URL, const char *name, 65 CURL **peasy, 66 struct t753_transfer_status *st) 67 { 68 CURL *easy = NULL; 69 CURLcode res = CURLE_OK; 70 71 *peasy = NULL; 72 memset(st, 0, sizeof(*st)); 73 st->name = name; 74 st->easy = easy; 75 st->pause = TRUE; 76 77 easy_init(easy); 78 79 easy_setopt(easy, CURLOPT_URL, URL); 80 easy_setopt(easy, CURLOPT_WRITEFUNCTION, t753_write_cb); 81 easy_setopt(easy, CURLOPT_WRITEDATA, st); 82 easy_setopt(easy, CURLOPT_HEADERFUNCTION, t753_hd_cb); 83 easy_setopt(easy, CURLOPT_HEADERDATA, st); 84 85 easy_setopt(easy, CURLOPT_NOPROGRESS, 1L); 86 easy_setopt(easy, CURLOPT_DEBUGDATA, &libtest_debug_config); 87 easy_setopt(easy, CURLOPT_DEBUGFUNCTION, libtest_debug_cb); 88 easy_setopt(easy, CURLOPT_VERBOSE, 1L); 89 90 *peasy = easy; 91 return TRUE; 92 93 test_cleanup: 94 if(easy) 95 curl_easy_cleanup(easy); 96 return FALSE; 97 } 98 99 static CURLcode test_lib753(char *URL) 100 { 101 CURL *easy1 = NULL, *easy2 = NULL; 102 CURLM *multi = NULL; 103 struct t753_transfer_status st1, st2; 104 CURLcode res = CURLE_OK; 105 CURLMcode mres; 106 int still_running; 107 108 start_test_timing(); 109 110 libtest_debug_config.nohex = 1; 111 libtest_debug_config.tracetime = 1; 112 113 curl_global_init(CURL_GLOBAL_DEFAULT); 114 115 curl_mfprintf(stderr, "init multi\n"); 116 multi = curl_multi_init(); 117 if(!multi) { 118 res = CURLE_OUT_OF_MEMORY; 119 goto test_cleanup; 120 } 121 122 if(!t753_setup(URL, "EASY1", &easy1, &st1)) 123 goto test_cleanup; 124 125 multi_add_handle(multi, easy1); 126 127 multi_perform(multi, &still_running); 128 abort_on_test_timeout(); 129 curl_mfprintf(stderr, "multi_perform() -> %d running\n", still_running); 130 131 while(still_running) { 132 int num; 133 134 /* The purpose of this Test: 135 * 1. Violently cleanup EASY1 *without* removing it from the multi 136 * handle first. This MUST discard the connection that EASY1 holds, 137 * as EASY1 is not DONE at this point. 138 * With the env var CURL_FTP_PWD_STOP set, the connection will 139 * have no outstanding data at this point. This would allow 140 * reuse if the connection is not terminated by the cleanup. 141 * 2. Add EASY2 for the same URL and observe in the expected result 142 * that the connection is NOT reused, e.g. all FTP commands 143 * are sent again on the new connection. 144 */ 145 if(easy1 && st1.seen_welcome) { 146 curl_easy_cleanup(easy1); 147 easy1 = NULL; 148 if(!easy2) { 149 if(!t753_setup(URL, "EASY2", &easy2, &st2)) 150 goto test_cleanup; 151 st2.pause = FALSE; 152 multi_add_handle(multi, easy2); 153 } 154 } 155 156 mres = curl_multi_wait(multi, NULL, 0, 1, &num); 157 if(mres != CURLM_OK) { 158 curl_mfprintf(stderr, "curl_multi_wait() returned %d\n", mres); 159 res = TEST_ERR_MAJOR_BAD; 160 goto test_cleanup; 161 } 162 163 abort_on_test_timeout(); 164 165 multi_perform(multi, &still_running); 166 curl_mfprintf(stderr, "multi_perform() -> %d running\n", still_running); 167 168 abort_on_test_timeout(); 169 } 170 171 test_cleanup: 172 173 if(res) 174 curl_mfprintf(stderr, "ERROR: %s\n", curl_easy_strerror(res)); 175 176 if(easy1) 177 curl_easy_cleanup(easy1); 178 if(easy2) 179 curl_easy_cleanup(easy2); 180 curl_multi_cleanup(multi); 181 curl_global_cleanup(); 182 183 return res; 184 }