lib2700.c (6377B)
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 #ifndef CURL_DISABLE_WEBSOCKETS 30 31 static const char *descr_flags(int flags) 32 { 33 if(flags & CURLWS_TEXT) 34 return flags & CURLWS_CONT ? "txt ---" : "txt fin"; 35 if(flags & CURLWS_BINARY) 36 return flags & CURLWS_CONT ? "bin ---" : "bin fin"; 37 if(flags & CURLWS_PING) 38 return "ping"; 39 if(flags & CURLWS_PONG) 40 return "pong"; 41 if(flags & CURLWS_CLOSE) 42 return "close"; 43 assert(false); 44 return ""; 45 } 46 47 static CURLcode send_header(CURL *curl, int flags, size_t size) 48 { 49 CURLcode res = CURLE_OK; 50 size_t nsent; 51 52 retry: 53 res = curl_ws_send(curl, NULL, 0, &nsent, (curl_off_t)size, 54 flags | CURLWS_OFFSET); 55 if(res == CURLE_AGAIN) { 56 assert(nsent == 0); 57 goto retry; 58 } 59 if(res) { 60 curl_mfprintf(stderr, "%s:%d curl_ws_send() failed with code %d (%s)\n", 61 __FILE__, __LINE__, res, curl_easy_strerror(res)); 62 assert(nsent == 0); 63 return res; 64 } 65 66 assert(nsent == 0); 67 68 return CURLE_OK; 69 } 70 71 static CURLcode recv_header(CURL *curl, int *flags, curl_off_t *offset, 72 curl_off_t *bytesleft) 73 { 74 CURLcode res = CURLE_OK; 75 size_t nread; 76 const struct curl_ws_frame *meta; 77 78 *flags = 0; 79 *offset = 0; 80 *bytesleft = 0; 81 82 retry: 83 res = curl_ws_recv(curl, NULL, 0, &nread, &meta); 84 if(res == CURLE_AGAIN) { 85 assert(nread == 0); 86 goto retry; 87 } 88 if(res) { 89 curl_mfprintf(stderr, "%s:%d curl_ws_recv() failed with code %d (%s)\n", 90 __FILE__, __LINE__, res, curl_easy_strerror(res)); 91 assert(nread == 0); 92 return res; 93 } 94 95 assert(nread == 0); 96 assert(meta != NULL); 97 assert(meta->flags); 98 assert(meta->offset == 0); 99 100 *flags = meta->flags; 101 *offset = meta->offset; 102 *bytesleft = meta->bytesleft; 103 104 curl_mfprintf(stdout, "%s [%" FMT_OFF_T "]", descr_flags(meta->flags), 105 meta->bytesleft); 106 107 if(meta->bytesleft > 0) 108 curl_mfprintf(stdout, " "); 109 110 res = send_header(curl, meta->flags, (size_t)meta->bytesleft); 111 if(res) 112 return res; 113 114 return CURLE_OK; 115 } 116 117 static CURLcode send_chunk(CURL *curl, int flags, const char *buffer, 118 size_t size, size_t *offset) 119 { 120 CURLcode res = CURLE_OK; 121 size_t nsent; 122 123 retry: 124 res = curl_ws_send(curl, buffer + *offset, size - *offset, &nsent, 0, 125 flags); 126 if(res == CURLE_AGAIN) { 127 assert(nsent == 0); 128 goto retry; 129 } 130 if(res) { 131 curl_mfprintf(stderr, "%s:%d curl_ws_send() failed with code %d (%s)\n", 132 __FILE__, __LINE__, res, curl_easy_strerror(res)); 133 assert(nsent == 0); 134 return res; 135 } 136 137 assert(nsent <= size - *offset); 138 139 *offset += nsent; 140 141 return CURLE_OK; 142 } 143 144 static CURLcode recv_chunk(CURL *curl, int flags, curl_off_t *offset, 145 curl_off_t *bytesleft) 146 { 147 CURLcode res = CURLE_OK; 148 char buffer[256]; 149 size_t nread; 150 const struct curl_ws_frame *meta; 151 size_t sendoffset = 0; 152 153 retry: 154 res = curl_ws_recv(curl, buffer, sizeof(buffer), &nread, &meta); 155 if(res == CURLE_AGAIN) { 156 assert(nread == 0); 157 goto retry; 158 } 159 if(res) { 160 curl_mfprintf(stderr, "%s:%d curl_ws_recv() failed with code %d (%s)\n", 161 __FILE__, __LINE__, res, curl_easy_strerror(res)); 162 assert(nread == 0); 163 return res; 164 } 165 166 assert(nread <= sizeof(buffer)); 167 assert(meta != NULL); 168 assert(meta->flags == flags); 169 assert(meta->offset == *offset); 170 assert(meta->bytesleft == (*bytesleft - (curl_off_t)nread)); 171 172 *offset += nread; 173 *bytesleft -= nread; 174 175 fwrite(buffer, 1, nread, stdout); 176 177 while(sendoffset < nread) { 178 res = send_chunk(curl, flags, buffer, nread, &sendoffset); 179 if(res) 180 return res; 181 } 182 183 return CURLE_OK; 184 } 185 186 static CURLcode recv_frame(CURL *curl, bool *stop) 187 { 188 CURLcode res = CURLE_OK; 189 int flags = 0; 190 curl_off_t offset = 0; 191 curl_off_t bytesleft = 0; 192 193 res = recv_header(curl, &flags, &offset, &bytesleft); 194 if(res) 195 return res; 196 197 while(bytesleft > 0) { 198 res = recv_chunk(curl, flags, &offset, &bytesleft); 199 if(res) 200 return res; 201 } 202 203 if(flags & CURLWS_CLOSE) 204 *stop = true; 205 206 curl_mfprintf(stdout, "\n"); 207 208 return res; 209 } 210 #endif 211 212 static CURLcode test_lib2700(char *URL) 213 { 214 #ifndef CURL_DISABLE_WEBSOCKETS 215 CURLcode res = CURLE_OK; 216 bool stop = false; 217 CURL *curl; 218 219 global_init(CURL_GLOBAL_ALL); 220 curl_global_trace("ws"); 221 easy_init(curl); 222 223 easy_setopt(curl, CURLOPT_URL, URL); 224 easy_setopt(curl, CURLOPT_USERAGENT, "client/test2700"); 225 libtest_debug_config.nohex = 1; 226 libtest_debug_config.tracetime = 1; 227 easy_setopt(curl, CURLOPT_DEBUGDATA, &libtest_debug_config); 228 easy_setopt(curl, CURLOPT_DEBUGFUNCTION, libtest_debug_cb); 229 easy_setopt(curl, CURLOPT_VERBOSE, 1L); 230 easy_setopt(curl, CURLOPT_CONNECT_ONLY, 2L); 231 if(!getenv("LIB2700_AUTO_PONG")) 232 easy_setopt(curl, CURLOPT_WS_OPTIONS, (long)CURLWS_NOAUTOPONG); 233 234 res = curl_easy_perform(curl); 235 if(res) { 236 curl_mfprintf(stderr, 237 "%s:%d curl_easy_perform() failed with code %d (%s)\n", 238 __FILE__, __LINE__, res, curl_easy_strerror(res)); 239 goto test_cleanup; 240 } 241 242 while(!stop) { 243 res = recv_frame(curl, &stop); 244 if(res) 245 goto test_cleanup; 246 } 247 248 test_cleanup: 249 curl_easy_cleanup(curl); 250 curl_global_cleanup(); 251 return res; 252 #else 253 NO_SUPPORT_BUILT_IN 254 #endif 255 }