113498266Sopenharmony_ci/*************************************************************************** 213498266Sopenharmony_ci * _ _ ____ _ 313498266Sopenharmony_ci * Project ___| | | | _ \| | 413498266Sopenharmony_ci * / __| | | | |_) | | 513498266Sopenharmony_ci * | (__| |_| | _ <| |___ 613498266Sopenharmony_ci * \___|\___/|_| \_\_____| 713498266Sopenharmony_ci * 813498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 913498266Sopenharmony_ci * 1013498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which 1113498266Sopenharmony_ci * you should have received as part of this distribution. The terms 1213498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html. 1313498266Sopenharmony_ci * 1413498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell 1513498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is 1613498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file. 1713498266Sopenharmony_ci * 1813498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 1913498266Sopenharmony_ci * KIND, either express or implied. 2013498266Sopenharmony_ci * 2113498266Sopenharmony_ci * SPDX-License-Identifier: curl 2213498266Sopenharmony_ci * 2313498266Sopenharmony_ci ***************************************************************************/ 2413498266Sopenharmony_ci#include "curlcheck.h" 2513498266Sopenharmony_ci 2613498266Sopenharmony_ci#include "urldata.h" 2713498266Sopenharmony_ci#include "bufq.h" 2813498266Sopenharmony_ci#include "curl_trc.h" 2913498266Sopenharmony_ci 3013498266Sopenharmony_cistatic CURLcode unit_setup(void) 3113498266Sopenharmony_ci{ 3213498266Sopenharmony_ci CURLcode res = CURLE_OK; 3313498266Sopenharmony_ci return res; 3413498266Sopenharmony_ci} 3513498266Sopenharmony_ci 3613498266Sopenharmony_cistatic void unit_stop(void) 3713498266Sopenharmony_ci{ 3813498266Sopenharmony_ci} 3913498266Sopenharmony_ci 4013498266Sopenharmony_cistatic const char *tail_err(struct bufq *q) 4113498266Sopenharmony_ci{ 4213498266Sopenharmony_ci struct buf_chunk *chunk; 4313498266Sopenharmony_ci 4413498266Sopenharmony_ci if(!q->tail) { 4513498266Sopenharmony_ci return q->head? "tail is NULL, but head is not" : NULL; 4613498266Sopenharmony_ci } 4713498266Sopenharmony_ci 4813498266Sopenharmony_ci chunk = q->head; 4913498266Sopenharmony_ci while(chunk) { 5013498266Sopenharmony_ci if(chunk == q->tail) { 5113498266Sopenharmony_ci if(chunk->next) { 5213498266Sopenharmony_ci return "tail points to queue, but not at the end"; 5313498266Sopenharmony_ci } 5413498266Sopenharmony_ci return NULL; 5513498266Sopenharmony_ci } 5613498266Sopenharmony_ci chunk = chunk->next; 5713498266Sopenharmony_ci } 5813498266Sopenharmony_ci return "tail not part of queue"; 5913498266Sopenharmony_ci} 6013498266Sopenharmony_ci 6113498266Sopenharmony_cistatic void dump_bufq(struct bufq *q, const char *msg) 6213498266Sopenharmony_ci{ 6313498266Sopenharmony_ci struct buf_chunk *chunk; 6413498266Sopenharmony_ci const char *terr; 6513498266Sopenharmony_ci size_t n; 6613498266Sopenharmony_ci 6713498266Sopenharmony_ci fprintf(stderr, "bufq[chunk_size=%zu, max_chunks=%zu] %s\n", 6813498266Sopenharmony_ci q->chunk_size, q->max_chunks, msg); 6913498266Sopenharmony_ci fprintf(stderr, "- queue[\n"); 7013498266Sopenharmony_ci chunk = q->head; 7113498266Sopenharmony_ci while(chunk) { 7213498266Sopenharmony_ci fprintf(stderr, " chunk[len=%zu, roff=%zu, woff=%zu]\n", 7313498266Sopenharmony_ci chunk->dlen, chunk->r_offset, chunk->w_offset); 7413498266Sopenharmony_ci chunk = chunk->next; 7513498266Sopenharmony_ci } 7613498266Sopenharmony_ci fprintf(stderr, " ]\n"); 7713498266Sopenharmony_ci terr = tail_err(q); 7813498266Sopenharmony_ci fprintf(stderr, "- tail: %s\n", terr? terr : "ok"); 7913498266Sopenharmony_ci n = 0; 8013498266Sopenharmony_ci chunk = q->spare; 8113498266Sopenharmony_ci while(chunk) { 8213498266Sopenharmony_ci ++n; 8313498266Sopenharmony_ci chunk = chunk->next; 8413498266Sopenharmony_ci } 8513498266Sopenharmony_ci fprintf(stderr, "- chunks: %zu\n", q->chunk_count); 8613498266Sopenharmony_ci fprintf(stderr, "- spares: %zu\n", n); 8713498266Sopenharmony_ci} 8813498266Sopenharmony_ci 8913498266Sopenharmony_cistatic unsigned char test_data[32*1024]; 9013498266Sopenharmony_ci 9113498266Sopenharmony_cistatic void check_bufq(size_t pool_spares, 9213498266Sopenharmony_ci size_t chunk_size, size_t max_chunks, 9313498266Sopenharmony_ci size_t wsize, size_t rsize, int opts) 9413498266Sopenharmony_ci{ 9513498266Sopenharmony_ci struct bufq q; 9613498266Sopenharmony_ci struct bufc_pool pool; 9713498266Sopenharmony_ci size_t max_len = chunk_size * max_chunks; 9813498266Sopenharmony_ci CURLcode result; 9913498266Sopenharmony_ci ssize_t n, i; 10013498266Sopenharmony_ci size_t nwritten, nread; 10113498266Sopenharmony_ci 10213498266Sopenharmony_ci if(pool_spares > 0) { 10313498266Sopenharmony_ci Curl_bufcp_init(&pool, chunk_size, pool_spares); 10413498266Sopenharmony_ci Curl_bufq_initp(&q, &pool, max_chunks, opts); 10513498266Sopenharmony_ci } 10613498266Sopenharmony_ci else { 10713498266Sopenharmony_ci Curl_bufq_init2(&q, chunk_size, max_chunks, opts); 10813498266Sopenharmony_ci } 10913498266Sopenharmony_ci 11013498266Sopenharmony_ci fail_unless(q.chunk_size == chunk_size, "chunk_size init wrong"); 11113498266Sopenharmony_ci fail_unless(q.max_chunks == max_chunks, "max_chunks init wrong"); 11213498266Sopenharmony_ci fail_unless(q.head == NULL, "init: head not NULL"); 11313498266Sopenharmony_ci fail_unless(q.tail == NULL, "init: tail not NULL"); 11413498266Sopenharmony_ci fail_unless(q.spare == NULL, "init: spare not NULL"); 11513498266Sopenharmony_ci fail_unless(Curl_bufq_len(&q) == 0, "init: bufq length != 0"); 11613498266Sopenharmony_ci 11713498266Sopenharmony_ci n = Curl_bufq_write(&q, test_data, wsize, &result); 11813498266Sopenharmony_ci fail_unless(n >= 0, "write: negative size returned"); 11913498266Sopenharmony_ci fail_unless((size_t)n <= wsize, "write: wrong size returned"); 12013498266Sopenharmony_ci fail_unless(result == CURLE_OK, "write: wrong result returned"); 12113498266Sopenharmony_ci 12213498266Sopenharmony_ci /* write empty bufq full */ 12313498266Sopenharmony_ci nwritten = 0; 12413498266Sopenharmony_ci Curl_bufq_reset(&q); 12513498266Sopenharmony_ci while(!Curl_bufq_is_full(&q)) { 12613498266Sopenharmony_ci n = Curl_bufq_write(&q, test_data, wsize, &result); 12713498266Sopenharmony_ci if(n >= 0) { 12813498266Sopenharmony_ci nwritten += (size_t)n; 12913498266Sopenharmony_ci } 13013498266Sopenharmony_ci else if(result != CURLE_AGAIN) { 13113498266Sopenharmony_ci fail_unless(result == CURLE_AGAIN, "write-loop: unexpected result"); 13213498266Sopenharmony_ci break; 13313498266Sopenharmony_ci } 13413498266Sopenharmony_ci } 13513498266Sopenharmony_ci if(nwritten != max_len) { 13613498266Sopenharmony_ci fprintf(stderr, "%zu bytes written, but max_len=%zu\n", 13713498266Sopenharmony_ci nwritten, max_len); 13813498266Sopenharmony_ci dump_bufq(&q, "after writing full"); 13913498266Sopenharmony_ci fail_if(TRUE, "write: bufq full but nwritten wrong"); 14013498266Sopenharmony_ci } 14113498266Sopenharmony_ci 14213498266Sopenharmony_ci /* read full bufq empty */ 14313498266Sopenharmony_ci nread = 0; 14413498266Sopenharmony_ci while(!Curl_bufq_is_empty(&q)) { 14513498266Sopenharmony_ci n = Curl_bufq_read(&q, test_data, rsize, &result); 14613498266Sopenharmony_ci if(n >= 0) { 14713498266Sopenharmony_ci nread += (size_t)n; 14813498266Sopenharmony_ci } 14913498266Sopenharmony_ci else if(result != CURLE_AGAIN) { 15013498266Sopenharmony_ci fail_unless(result == CURLE_AGAIN, "read-loop: unexpected result"); 15113498266Sopenharmony_ci break; 15213498266Sopenharmony_ci } 15313498266Sopenharmony_ci } 15413498266Sopenharmony_ci if(nread != max_len) { 15513498266Sopenharmony_ci fprintf(stderr, "%zu bytes read, but max_len=%zu\n", 15613498266Sopenharmony_ci nwritten, max_len); 15713498266Sopenharmony_ci dump_bufq(&q, "after reading empty"); 15813498266Sopenharmony_ci fail_if(TRUE, "read: bufq empty but nread wrong"); 15913498266Sopenharmony_ci } 16013498266Sopenharmony_ci if(q.tail) { 16113498266Sopenharmony_ci dump_bufq(&q, "after reading empty"); 16213498266Sopenharmony_ci fail_if(TRUE, "read empty, but tail is not NULL"); 16313498266Sopenharmony_ci } 16413498266Sopenharmony_ci 16513498266Sopenharmony_ci for(i = 0; i < 1000; ++i) { 16613498266Sopenharmony_ci n = Curl_bufq_write(&q, test_data, wsize, &result); 16713498266Sopenharmony_ci if(n < 0 && result != CURLE_AGAIN) { 16813498266Sopenharmony_ci fail_unless(result == CURLE_AGAIN, "rw-loop: unexpected write result"); 16913498266Sopenharmony_ci break; 17013498266Sopenharmony_ci } 17113498266Sopenharmony_ci n = Curl_bufq_read(&q, test_data, rsize, &result); 17213498266Sopenharmony_ci if(n < 0 && result != CURLE_AGAIN) { 17313498266Sopenharmony_ci fail_unless(result == CURLE_AGAIN, "rw-loop: unexpected read result"); 17413498266Sopenharmony_ci break; 17513498266Sopenharmony_ci } 17613498266Sopenharmony_ci } 17713498266Sopenharmony_ci 17813498266Sopenharmony_ci /* Test SOFT_LIMIT option */ 17913498266Sopenharmony_ci Curl_bufq_free(&q); 18013498266Sopenharmony_ci Curl_bufq_init2(&q, chunk_size, max_chunks, (opts|BUFQ_OPT_SOFT_LIMIT)); 18113498266Sopenharmony_ci nwritten = 0; 18213498266Sopenharmony_ci while(!Curl_bufq_is_full(&q)) { 18313498266Sopenharmony_ci n = Curl_bufq_write(&q, test_data, wsize, &result); 18413498266Sopenharmony_ci if(n < 0 || (size_t)n != wsize) { 18513498266Sopenharmony_ci fail_unless(n > 0 && (size_t)n == wsize, "write should be complete"); 18613498266Sopenharmony_ci break; 18713498266Sopenharmony_ci } 18813498266Sopenharmony_ci nwritten += (size_t)n; 18913498266Sopenharmony_ci } 19013498266Sopenharmony_ci if(nwritten < max_len) { 19113498266Sopenharmony_ci fprintf(stderr, "%zu bytes written, but max_len=%zu\n", 19213498266Sopenharmony_ci nwritten, max_len); 19313498266Sopenharmony_ci dump_bufq(&q, "after writing full"); 19413498266Sopenharmony_ci fail_if(TRUE, "write: bufq full but nwritten wrong"); 19513498266Sopenharmony_ci } 19613498266Sopenharmony_ci /* do one more write on a full bufq, should work */ 19713498266Sopenharmony_ci n = Curl_bufq_write(&q, test_data, wsize, &result); 19813498266Sopenharmony_ci fail_unless(n > 0 && (size_t)n == wsize, "write should be complete"); 19913498266Sopenharmony_ci nwritten += (size_t)n; 20013498266Sopenharmony_ci /* see that we get all out again */ 20113498266Sopenharmony_ci nread = 0; 20213498266Sopenharmony_ci while(!Curl_bufq_is_empty(&q)) { 20313498266Sopenharmony_ci n = Curl_bufq_read(&q, test_data, rsize, &result); 20413498266Sopenharmony_ci if(n <= 0) { 20513498266Sopenharmony_ci fail_unless(n > 0, "read-loop: unexpected fail"); 20613498266Sopenharmony_ci break; 20713498266Sopenharmony_ci } 20813498266Sopenharmony_ci nread += (size_t)n; 20913498266Sopenharmony_ci } 21013498266Sopenharmony_ci fail_unless(nread == nwritten, "did not get the same out as put in"); 21113498266Sopenharmony_ci 21213498266Sopenharmony_ci dump_bufq(&q, "at end of test"); 21313498266Sopenharmony_ci Curl_bufq_free(&q); 21413498266Sopenharmony_ci if(pool_spares > 0) 21513498266Sopenharmony_ci Curl_bufcp_free(&pool); 21613498266Sopenharmony_ci} 21713498266Sopenharmony_ci 21813498266Sopenharmony_ciUNITTEST_START 21913498266Sopenharmony_ci struct bufq q; 22013498266Sopenharmony_ci ssize_t n; 22113498266Sopenharmony_ci CURLcode result; 22213498266Sopenharmony_ci unsigned char buf[16*1024]; 22313498266Sopenharmony_ci 22413498266Sopenharmony_ci Curl_bufq_init(&q, 8*1024, 12); 22513498266Sopenharmony_ci n = Curl_bufq_read(&q, buf, 128, &result); 22613498266Sopenharmony_ci fail_unless(n < 0 && result == CURLE_AGAIN, "read empty fail"); 22713498266Sopenharmony_ci Curl_bufq_free(&q); 22813498266Sopenharmony_ci 22913498266Sopenharmony_ci check_bufq(0, 1024, 4, 128, 128, BUFQ_OPT_NONE); 23013498266Sopenharmony_ci check_bufq(0, 1024, 4, 129, 127, BUFQ_OPT_NONE); 23113498266Sopenharmony_ci check_bufq(0, 1024, 4, 2000, 16000, BUFQ_OPT_NONE); 23213498266Sopenharmony_ci check_bufq(0, 1024, 4, 16000, 3000, BUFQ_OPT_NONE); 23313498266Sopenharmony_ci 23413498266Sopenharmony_ci check_bufq(0, 8000, 10, 1234, 1234, BUFQ_OPT_NONE); 23513498266Sopenharmony_ci check_bufq(0, 8000, 10, 8*1024, 4*1024, BUFQ_OPT_NONE); 23613498266Sopenharmony_ci 23713498266Sopenharmony_ci check_bufq(0, 1024, 4, 128, 128, BUFQ_OPT_NO_SPARES); 23813498266Sopenharmony_ci check_bufq(0, 1024, 4, 129, 127, BUFQ_OPT_NO_SPARES); 23913498266Sopenharmony_ci check_bufq(0, 1024, 4, 2000, 16000, BUFQ_OPT_NO_SPARES); 24013498266Sopenharmony_ci check_bufq(0, 1024, 4, 16000, 3000, BUFQ_OPT_NO_SPARES); 24113498266Sopenharmony_ci 24213498266Sopenharmony_ci check_bufq(8, 1024, 4, 128, 128, BUFQ_OPT_NONE); 24313498266Sopenharmony_ci check_bufq(8, 8000, 10, 1234, 1234, BUFQ_OPT_NONE); 24413498266Sopenharmony_ci check_bufq(8, 1024, 4, 129, 127, BUFQ_OPT_NO_SPARES); 24513498266Sopenharmony_ci 24613498266Sopenharmony_ciUNITTEST_STOP 247