From: Daniel Stenberg Date: Sat, 10 Aug 2024 21:27:25 +0000 (+0200) Subject: llist: remove direct struct accesses, use only functions X-Git-Tag: curl-8_10_0~298 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ba235ab269080dc66e35835c829f7ac4290dbc1d;p=thirdparty%2Fcurl.git llist: remove direct struct accesses, use only functions - Turned them all into functions to also do asserts etc. - The llist related structs got all their fields renamed in order to make sure no existing code remains using direct access. - Each list node struct now points back to the list it "lives in", so Curl_node_remove() no longer needs the list pointer. - Rename the node struct and some of the access functions. - Added lots of ASSERTs to verify API being used correctly - Fix some cases of API misuse Add docs/LLIST.md documenting the internal linked list API. Closes #14485 --- diff --git a/docs/LLIST.md b/docs/LLIST.md new file mode 100644 index 0000000000..ee9a89badb --- /dev/null +++ b/docs/LLIST.md @@ -0,0 +1,190 @@ + + +# `llist` - linked lists + + #include "llist.h" + +This is the internal module for linked lists. The API is designed to be +flexible but also to avoid dynamic memory allocation. + +None of the involved structs should be accessed using struct fields (outside +of `llist.c`). Use the functions. + +## Setup and shutdown + +`struct Curl_llist` is the struct holding a single linked list. It needs to be +initialized with a call to `Curl_llist_init()` before it can be used + +To clean up a list, call `Curl_llist_destroy()`. Since the linked lists +themselves do not allocate memory, it can also be fine to just *not* clean up +the list. + +## Add a node + +There are two functions for adding a node to a linked list: + +1. Add it last in the list with `Curl_llist_append` +2. Add it after a specific existing node with `Curl_llist_insert_next` + +When a node is added to a list, it stores an associated custom pointer to +anything you like and you provide a pointer to a `struct Curl_llist_node` +struct in which it stores and updates pointers. If you intend to add the same +struct to multiple lists concurrently, you need to have one `struct +Curl_llist_node` for each list. + +Add a node to a list with `Curl_llist_append(list, elem, node)`. Where + +- `list`: points to a `struct Curl_llist` +- `elem`: points to what you want added to the list +- `node`: is a pointer to a `struct Curl_llist_node`. Data storage for this + node. + +Example: to add a `struct foobar` to a linked list. Add a node struct within +it: + + struct foobar { + char *random; + struct Curl_llist_node storage; /* can be anywhere in the struct */ + char *data; + }; + + struct Curl_llist barlist; /* the list for foobar entries */ + struct foobar entries[10]; + + Curl_llist_init(&barlist, NULL); + + /* add the first struct to the list */ + Curl_llist_append(&barlist, &entries[0], &entries[0].storage); + +See also `Curl_llist_insert_next`. + +## Remove a node + +Remove a node again from a list by calling `Curl_llist_remove()`. + +## Iterate + +To iterate over a list: first get the head entry and then iterate over the +nodes as long there is a next. Each node has an *element* associated with it, +the custom pointer you stored there. Usually a struct pointer or similar. + + struct Curl_llist_node *iter; + + /* get the first entry of the 'barlist' */ + iter = Curl_llist_head(&barlist); + + while(iter) { + /* extract the element pointer from the node */ + struct foobar *elem = Curl_node_elem(iter); + + /* advance to the next node in the list */ + iter = Curl_node_next(iter); + } + +# Function overview + +## `Curl_llist_init` + +~~~c +void Curl_llist_init(struct Curl_llist *list, Curl_llist_dtor dtor); +~~~ + +Initializes the `list`. The argument `dtor` is NULL or a function pointer that +gets called when list nodes are removed from this list. + +The function is infallible. + +~~~c +typedef void (*Curl_llist_dtor)(void *user, void *elem); +~~~ + +`dtor` is called with two arguments: `user` and `elem`. The first being the +`user` pointer passed in to `Curl_llist_remove()`or `Curl_llist_destroy()` and +the second is the `elem` pointer associated with removed node. The pointer +that `Curl_node_elem()` would have returned for that node. + +## `Curl_llist_destroy` + +~~~c +void Curl_llist_destroy(struct Curl_llist *list, void *user); +~~~ + +This removes all nodes from the `list`. This leaves the list in a cleared +state. + +The function is infallible. + +## `Curl_llist_append` + +~~~c +void Curl_llist_append(struct Curl_llist *list, + const void *elem, struct Curl_llist_node *node); +~~~ + +Adds `node` last in the `list` with a custom pointer to `elem`. + +The function is infallible. + +## `Curl_llist_insert_next` + +~~~c +void Curl_llist_insert_next(struct Curl_llist *list, + struct Curl_llist_node *node, + const void *elem, + struct Curl_llist_node *node); +~~~ + +Adds `node` to the `list` with a custom pointer to `elem` immediately after +the previous list `node`. + +The function is infallible. + +## `Curl_llist_head` + +~~~c +struct Curl_llist_node *Curl_llist_head(struct Curl_llist *list); +~~~ + +Returns a pointer to the first node of the `list`, or a NULL if empty. + +## `Curl_node_uremove` + +~~~c +void Curl_node_uremove(struct Curl_llist_node *node, void *user); +~~~ + +Removes the `node` the list it was previously added to. Passes the `user` +pointer to the list's destructor function if one was setup. + +The function is infallible. + +## `Curl_node_remove` + +~~~c +void Curl_node_remove(struct Curl_llist_node *node); +~~~ + +Removes the `node` the list it was previously added to. Passes a NULL pointer +to the list's destructor function if one was setup. + +The function is infallible. + +## `Curl_node_elem` + +~~~c +void *Curl_node_elem(struct Curl_llist_node *node); +~~~ + +Given a list node, this function returns the associated element. + +## `Curl_node_next` + +~~~c +struct Curl_llist_node *Curl_node_next(struct Curl_llist_node *node); +~~~ + +Given a list node, this function returns the next node in the list. diff --git a/docs/Makefile.am b/docs/Makefile.am index e9ef628486..5db134b4e0 100644 --- a/docs/Makefile.am +++ b/docs/Makefile.am @@ -81,6 +81,7 @@ EXTRA_DIST = \ INSTALL.md \ INTERNALS.md \ IPFS.md \ + LLIST.md \ KNOWN_BUGS \ MAIL-ETIQUETTE.md \ MANUAL.md \ diff --git a/lib/altsvc.c b/lib/altsvc.c index db9749c258..dcedc491c5 100644 --- a/lib/altsvc.c +++ b/lib/altsvc.c @@ -337,13 +337,13 @@ CURLcode Curl_altsvc_ctrl(struct altsvcinfo *asi, const long ctrl) */ void Curl_altsvc_cleanup(struct altsvcinfo **altsvcp) { - struct Curl_llist_element *e; - struct Curl_llist_element *n; if(*altsvcp) { + struct Curl_llist_node *e; + struct Curl_llist_node *n; struct altsvcinfo *altsvc = *altsvcp; - for(e = altsvc->list.head; e; e = n) { - struct altsvc *as = e->ptr; - n = e->next; + for(e = Curl_llist_head(&altsvc->list); e; e = n) { + struct altsvc *as = Curl_node_elem(e); + n = Curl_node_next(e); altsvc_free(as); } free(altsvc->filename); @@ -358,8 +358,6 @@ void Curl_altsvc_cleanup(struct altsvcinfo **altsvcp) CURLcode Curl_altsvc_save(struct Curl_easy *data, struct altsvcinfo *altsvc, const char *file) { - struct Curl_llist_element *e; - struct Curl_llist_element *n; CURLcode result = CURLE_OK; FILE *out; char *tempstore = NULL; @@ -378,12 +376,14 @@ CURLcode Curl_altsvc_save(struct Curl_easy *data, result = Curl_fopen(data, file, &out, &tempstore); if(!result) { + struct Curl_llist_node *e; + struct Curl_llist_node *n; fputs("# Your alt-svc cache. https://curl.se/docs/alt-svc.html\n" "# This file was generated by libcurl! Edit at your own risk.\n", out); - for(e = altsvc->list.head; e; e = n) { - struct altsvc *as = e->ptr; - n = e->next; + for(e = Curl_llist_head(&altsvc->list); e; e = n) { + struct altsvc *as = Curl_node_elem(e); + n = Curl_node_next(e); result = altsvc_out(as, out); if(result) break; @@ -440,15 +440,15 @@ static bool hostcompare(const char *host, const char *check) static void altsvc_flush(struct altsvcinfo *asi, enum alpnid srcalpnid, const char *srchost, unsigned short srcport) { - struct Curl_llist_element *e; - struct Curl_llist_element *n; - for(e = asi->list.head; e; e = n) { - struct altsvc *as = e->ptr; - n = e->next; + struct Curl_llist_node *e; + struct Curl_llist_node *n; + for(e = Curl_llist_head(&asi->list); e; e = n) { + struct altsvc *as = Curl_node_elem(e); + n = Curl_node_next(e); if((srcalpnid == as->src.alpnid) && (srcport == as->src.port) && hostcompare(srchost, as->src.host)) { - Curl_llist_remove(&asi->list, e, NULL); + Curl_node_remove(e); altsvc_free(as); } } @@ -677,19 +677,19 @@ bool Curl_altsvc_lookup(struct altsvcinfo *asi, struct altsvc **dstentry, const int versions) /* one or more bits */ { - struct Curl_llist_element *e; - struct Curl_llist_element *n; + struct Curl_llist_node *e; + struct Curl_llist_node *n; time_t now = time(NULL); DEBUGASSERT(asi); DEBUGASSERT(srchost); DEBUGASSERT(dstentry); - for(e = asi->list.head; e; e = n) { - struct altsvc *as = e->ptr; - n = e->next; + for(e = Curl_llist_head(&asi->list); e; e = n) { + struct altsvc *as = Curl_node_elem(e); + n = Curl_node_next(e); if(as->expires < now) { /* an expired entry, remove */ - Curl_llist_remove(&asi->list, e, NULL); + Curl_node_remove(e); altsvc_free(as); continue; } diff --git a/lib/altsvc.h b/lib/altsvc.h index 58f1905da6..48999efb31 100644 --- a/lib/altsvc.h +++ b/lib/altsvc.h @@ -48,7 +48,7 @@ struct altsvc { time_t expires; bool persist; unsigned int prio; - struct Curl_llist_element node; + struct Curl_llist_node node; }; struct altsvcinfo { diff --git a/lib/conncache.c b/lib/conncache.c index 5de10de914..e0a15cf32c 100644 --- a/lib/conncache.c +++ b/lib/conncache.c @@ -99,17 +99,15 @@ static void bundle_add_conn(struct connectbundle *bundle, static int bundle_remove_conn(struct connectbundle *bundle, struct connectdata *conn) { - struct Curl_llist_element *curr; - - curr = bundle->conn_list.head; + struct Curl_llist_node *curr = Curl_llist_head(&bundle->conn_list); while(curr) { - if(curr->ptr == conn) { - Curl_llist_remove(&bundle->conn_list, curr, NULL); + if(Curl_node_elem(curr) == conn) { + Curl_node_remove(curr); bundle->num_connections--; conn->bundle = NULL; return 1; /* we removed a handle */ } - curr = curr->next; + curr = Curl_node_next(curr); } DEBUGASSERT(0); return 0; @@ -149,7 +147,6 @@ void Curl_conncache_destroy(struct conncache *connc) if(connc) { Curl_hash_destroy(&connc->hash); connc->multi = NULL; - DEBUGASSERT(!Curl_llist_count(&connc->shutdowns.conn_list)); } } @@ -341,7 +338,6 @@ bool Curl_conncache_foreach(struct Curl_easy *data, struct connectdata *conn, void *param)) { struct Curl_hash_iterator iter; - struct Curl_llist_element *curr; struct Curl_hash_element *he; if(!connc) @@ -352,17 +348,16 @@ bool Curl_conncache_foreach(struct Curl_easy *data, he = Curl_hash_next_element(&iter); while(he) { - struct connectbundle *bundle; - - bundle = he->ptr; + struct Curl_llist_node *curr; + struct connectbundle *bundle = he->ptr; he = Curl_hash_next_element(&iter); - curr = bundle->conn_list.head; + curr = Curl_llist_head(&bundle->conn_list); while(curr) { /* Yes, we need to update curr before calling func(), because func() might decide to remove the connection */ - struct connectdata *conn = curr->ptr; - curr = curr->next; + struct connectdata *conn = Curl_node_elem(curr); + curr = Curl_node_next(curr); if(1 == func(data, conn, param)) { CONNCACHE_UNLOCK(data); @@ -391,12 +386,12 @@ connc_find_first_connection(struct conncache *connc) he = Curl_hash_next_element(&iter); while(he) { - struct Curl_llist_element *curr; + struct Curl_llist_node *curr; bundle = he->ptr; - curr = bundle->conn_list.head; + curr = Curl_llist_head(&bundle->conn_list); if(curr) { - return curr->ptr; + return Curl_node_elem(curr); } he = Curl_hash_next_element(&iter); @@ -451,7 +446,7 @@ struct connectdata * Curl_conncache_extract_bundle(struct Curl_easy *data, struct connectbundle *bundle) { - struct Curl_llist_element *curr; + struct Curl_llist_node *curr; timediff_t highscore = -1; timediff_t score; struct curltime now; @@ -462,9 +457,9 @@ Curl_conncache_extract_bundle(struct Curl_easy *data, now = Curl_now(); - curr = bundle->conn_list.head; + curr = Curl_llist_head(&bundle->conn_list); while(curr) { - conn = curr->ptr; + conn = Curl_node_elem(curr); if(!CONN_INUSE(conn)) { /* Set higher score for the age passed since the connection was used */ @@ -475,7 +470,7 @@ Curl_conncache_extract_bundle(struct Curl_easy *data, conn_candidate = conn; } } - curr = curr->next; + curr = Curl_node_next(curr); } if(conn_candidate) { /* remove it to prevent another thread from nicking it */ @@ -499,7 +494,7 @@ Curl_conncache_extract_oldest(struct Curl_easy *data) { struct conncache *connc = data->state.conn_cache; struct Curl_hash_iterator iter; - struct Curl_llist_element *curr; + struct Curl_llist_node *curr; struct Curl_hash_element *he; timediff_t highscore =- 1; timediff_t score; @@ -519,9 +514,9 @@ Curl_conncache_extract_oldest(struct Curl_easy *data) bundle = he->ptr; - curr = bundle->conn_list.head; + curr = Curl_llist_head(&bundle->conn_list); while(curr) { - conn = curr->ptr; + conn = Curl_node_elem(curr); if(!CONN_INUSE(conn) && !conn->bits.close && !conn->connect_only) { @@ -534,7 +529,7 @@ Curl_conncache_extract_oldest(struct Curl_easy *data) bundle_candidate = bundle; } } - curr = curr->next; + curr = Curl_node_next(curr); } he = Curl_hash_next_element(&iter); @@ -553,7 +548,7 @@ Curl_conncache_extract_oldest(struct Curl_easy *data) static void connc_shutdown_discard_all(struct conncache *connc) { - struct Curl_llist_element *e = connc->shutdowns.conn_list.head; + struct Curl_llist_node *e = Curl_llist_head(&connc->shutdowns.conn_list); struct connectdata *conn; if(!e) @@ -563,12 +558,12 @@ static void connc_shutdown_discard_all(struct conncache *connc) DEBUGASSERT(!connc->shutdowns.iter_locked); connc->shutdowns.iter_locked = TRUE; while(e) { - conn = e->ptr; - Curl_llist_remove(&connc->shutdowns.conn_list, e, NULL); + conn = Curl_node_elem(e); + Curl_node_remove(e); DEBUGF(infof(connc->closure_handle, "discard connection #%" CURL_FORMAT_CURL_OFF_T, conn->connection_id)); connc_disconnect(NULL, conn, connc, FALSE); - e = connc->shutdowns.conn_list.head; + e = Curl_llist_head(&connc->shutdowns.conn_list); } connc->shutdowns.iter_locked = FALSE; } @@ -626,18 +621,18 @@ void Curl_conncache_close_all_connections(struct conncache *connc) static void connc_shutdown_discard_oldest(struct conncache *connc) { - struct Curl_llist_element *e; + struct Curl_llist_node *e; struct connectdata *conn; DEBUGASSERT(!connc->shutdowns.iter_locked); if(connc->shutdowns.iter_locked) return; - e = connc->shutdowns.conn_list.head; + e = Curl_llist_head(&connc->shutdowns.conn_list); if(e) { SIGPIPE_VARIABLE(pipe_st); - conn = e->ptr; - Curl_llist_remove(&connc->shutdowns.conn_list, e, NULL); + conn = Curl_node_elem(e); + Curl_node_remove(e); sigpipe_init(&pipe_st); sigpipe_apply(connc->closure_handle, &pipe_st); connc_disconnect(NULL, conn, connc, FALSE); @@ -840,13 +835,14 @@ CURLcode Curl_conncache_add_pollfds(struct conncache *connc, DEBUGASSERT(!connc->shutdowns.iter_locked); connc->shutdowns.iter_locked = TRUE; - if(connc->shutdowns.conn_list.head) { - struct Curl_llist_element *e; + if(Curl_llist_head(&connc->shutdowns.conn_list)) { + struct Curl_llist_node *e; struct easy_pollset ps; struct connectdata *conn; - for(e = connc->shutdowns.conn_list.head; e; e = e->next) { - conn = e->ptr; + for(e = Curl_llist_head(&connc->shutdowns.conn_list); e; + e = Curl_node_next(e)) { + conn = Curl_node_elem(e); memset(&ps, 0, sizeof(ps)); Curl_attach_connection(connc->closure_handle, conn); Curl_conn_adjust_pollset(connc->closure_handle, &ps); @@ -871,13 +867,14 @@ CURLcode Curl_conncache_add_waitfds(struct conncache *connc, DEBUGASSERT(!connc->shutdowns.iter_locked); connc->shutdowns.iter_locked = TRUE; - if(connc->shutdowns.conn_list.head) { - struct Curl_llist_element *e; + if(Curl_llist_head(&connc->shutdowns.conn_list)) { + struct Curl_llist_node *e; struct easy_pollset ps; struct connectdata *conn; - for(e = connc->shutdowns.conn_list.head; e; e = e->next) { - conn = e->ptr; + for(e = Curl_llist_head(&connc->shutdowns.conn_list); e; + e = Curl_node_next(e)) { + conn = Curl_node_elem(e); memset(&ps, 0, sizeof(ps)); Curl_attach_connection(connc->closure_handle, conn); Curl_conn_adjust_pollset(connc->closure_handle, &ps); @@ -896,8 +893,8 @@ out: static void connc_perform(struct conncache *connc) { struct Curl_easy *data = connc->closure_handle; - struct Curl_llist_element *e = connc->shutdowns.conn_list.head; - struct Curl_llist_element *enext; + struct Curl_llist_node *e = Curl_llist_head(&connc->shutdowns.conn_list); + struct Curl_llist_node *enext; struct connectdata *conn; struct curltime *nowp = NULL; struct curltime now; @@ -913,15 +910,15 @@ static void connc_perform(struct conncache *connc) Curl_llist_count(&connc->shutdowns.conn_list))); connc->shutdowns.iter_locked = TRUE; while(e) { - enext = e->next; - conn = e->ptr; + enext = Curl_node_next(e); + conn = Curl_node_elem(e); Curl_attach_connection(data, conn); connc_run_conn_shutdown(data, conn, &done); DEBUGF(infof(data, "[CCACHE] shutdown #%" CURL_FORMAT_CURL_OFF_T ", done=%d", conn->connection_id, done)); Curl_detach_connection(data); if(done) { - Curl_llist_remove(&connc->shutdowns.conn_list, e, NULL); + Curl_node_remove(e); connc_disconnect(NULL, conn, connc, FALSE); } else { @@ -1039,7 +1036,7 @@ void Curl_conncache_multi_socket(struct Curl_multi *multi, { struct conncache *connc = &multi->conn_cache; struct Curl_easy *data = connc->closure_handle; - struct Curl_llist_element *e = connc->shutdowns.conn_list.head; + struct Curl_llist_node *e = Curl_llist_head(&connc->shutdowns.conn_list); struct connectdata *conn; bool done; @@ -1050,7 +1047,7 @@ void Curl_conncache_multi_socket(struct Curl_multi *multi, connc->shutdowns.iter_locked = TRUE; while(e) { - conn = e->ptr; + conn = Curl_node_elem(e); if(s == conn->sock[FIRSTSOCKET] || s == conn->sock[SECONDARYSOCKET]) { Curl_attach_connection(data, conn); connc_run_conn_shutdown(data, conn, &done); @@ -1058,12 +1055,12 @@ void Curl_conncache_multi_socket(struct Curl_multi *multi, ", done=%d", conn->connection_id, done)); Curl_detach_connection(data); if(done || connc_update_shutdown_ev(multi, data, conn)) { - Curl_llist_remove(&connc->shutdowns.conn_list, e, NULL); + Curl_node_remove(e); connc_disconnect(NULL, conn, connc, FALSE); } break; } - e = e->next; + e = Curl_node_next(e); } connc->shutdowns.iter_locked = FALSE; } @@ -1119,13 +1116,13 @@ static void connc_shutdown_all(struct conncache *connc, int timeout_ms) } DEBUGASSERT(!connc->shutdowns.iter_locked); - while(connc->shutdowns.conn_list.head) { + while(Curl_llist_head(&connc->shutdowns.conn_list)) { timediff_t timespent; int remain_ms; connc_perform(connc); - if(!connc->shutdowns.conn_list.head) { + if(!Curl_llist_head(&connc->shutdowns.conn_list)) { DEBUGF(infof(data, "conncache shutdown ok")); break; } @@ -1154,7 +1151,7 @@ static void connc_shutdown_all(struct conncache *connc, int timeout_ms) void Curl_conncache_print(struct conncache *connc) { struct Curl_hash_iterator iter; - struct Curl_llist_element *curr; + struct Curl_llist_node *curr; struct Curl_hash_element *he; if(!connc) @@ -1172,12 +1169,12 @@ void Curl_conncache_print(struct conncache *connc) bundle = he->ptr; fprintf(stderr, "%s -", he->key); - curr = bundle->conn_list->head; + curr = Curl_llist_head(bundle->conn_list); while(curr) { - conn = curr->ptr; + conn = Curl_node_elem(curr); fprintf(stderr, " [%p %d]", (void *)conn, conn->refcount); - curr = curr->next; + curr = Curl_node_next(curr); } fprintf(stderr, "\n"); diff --git a/lib/easy.c b/lib/easy.c index 6c4594904b..34e8f90f12 100644 --- a/lib/easy.c +++ b/lib/easy.c @@ -597,10 +597,10 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev) } else { /* here pollrc is > 0 */ - struct Curl_llist_element *e = multi->process.head; + struct Curl_llist_node *e = Curl_llist_head(&multi->process); struct Curl_easy *data; DEBUGASSERT(e); - data = e->ptr; + data = Curl_node_elem(e); DEBUGASSERT(data); /* loop over the monitored sockets to see which ones had activity */ @@ -1018,7 +1018,9 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) goto fail; } #endif /* USE_ARES */ - +#ifndef CURL_DISABLE_HTTP + Curl_llist_init(&outcurl->state.httphdrs, NULL); +#endif Curl_initinfo(outcurl); outcurl->magic = CURLEASY_MAGIC_NUMBER; diff --git a/lib/fileinfo.h b/lib/fileinfo.h index ce009da06d..0b3f56d9d4 100644 --- a/lib/fileinfo.h +++ b/lib/fileinfo.h @@ -30,7 +30,7 @@ struct fileinfo { struct curl_fileinfo info; - struct Curl_llist_element list; + struct Curl_llist_node list; struct dynbuf buf; }; diff --git a/lib/ftp.c b/lib/ftp.c index 9b2db62706..fcb540a6b1 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -4037,7 +4037,7 @@ static CURLcode wc_statemach(struct Curl_easy *data) wildcard->state = CURLWC_CLEAN; continue; } - if(wildcard->filelist.size == 0) { + if(Curl_llist_count(&wildcard->filelist) == 0) { /* no corresponding file */ wildcard->state = CURLWC_CLEAN; return CURLE_REMOTE_FILE_NOT_FOUND; @@ -4048,7 +4048,8 @@ static CURLcode wc_statemach(struct Curl_easy *data) case CURLWC_DOWNLOADING: { /* filelist has at least one file, lets get first one */ struct ftp_conn *ftpc = &conn->proto.ftpc; - struct curl_fileinfo *finfo = wildcard->filelist.head->ptr; + struct Curl_llist_node *head = Curl_llist_head(&wildcard->filelist); + struct curl_fileinfo *finfo = Curl_node_elem(head); struct FTP *ftp = data->req.p.ftp; char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename); @@ -4064,7 +4065,8 @@ static CURLcode wc_statemach(struct Curl_easy *data) long userresponse; Curl_set_in_callback(data, true); userresponse = data->set.chunk_bgn( - finfo, data->set.wildcardptr, (int)wildcard->filelist.size); + finfo, data->set.wildcardptr, + (int)Curl_llist_count(&wildcard->filelist)); Curl_set_in_callback(data, false); switch(userresponse) { case CURL_CHUNK_BGN_FUNC_SKIP: @@ -4090,9 +4092,10 @@ static CURLcode wc_statemach(struct Curl_easy *data) return result; /* we do not need the Curl_fileinfo of first file anymore */ - Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL); + Curl_node_remove(Curl_llist_head(&wildcard->filelist)); - if(wildcard->filelist.size == 0) { /* remains only one file to down. */ + if(Curl_llist_count(&wildcard->filelist) == 0) { + /* remains only one file to down. */ wildcard->state = CURLWC_CLEAN; /* after that will be ftp_do called once again and no transfer will be done because of CURLWC_CLEAN state */ @@ -4107,8 +4110,8 @@ static CURLcode wc_statemach(struct Curl_easy *data) data->set.chunk_end(data->set.wildcardptr); Curl_set_in_callback(data, false); } - Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL); - wildcard->state = (wildcard->filelist.size == 0) ? + Curl_node_remove(Curl_llist_head(&wildcard->filelist)); + wildcard->state = (Curl_llist_count(&wildcard->filelist) == 0) ? CURLWC_CLEAN : CURLWC_DOWNLOADING; continue; } diff --git a/lib/hash.c b/lib/hash.c index df8e2abffe..be36704eb2 100644 --- a/lib/hash.c +++ b/lib/hash.c @@ -102,7 +102,7 @@ void *Curl_hash_add2(struct Curl_hash *h, void *key, size_t key_len, void *p, Curl_hash_elem_dtor dtor) { struct Curl_hash_element *he; - struct Curl_llist_element *le; + struct Curl_llist_node *le; struct Curl_llist *l; DEBUGASSERT(h); @@ -118,10 +118,10 @@ void *Curl_hash_add2(struct Curl_hash *h, void *key, size_t key_len, void *p, l = FETCH_LIST(h, key, key_len); - for(le = l->head; le; le = le->next) { - he = (struct Curl_hash_element *) le->ptr; + for(le = Curl_llist_head(l); le; le = Curl_node_next(le)) { + he = (struct Curl_hash_element *) Curl_node_elem(le); if(h->comp_func(he->key, he->key_len, key, key_len)) { - Curl_llist_remove(l, le, (void *)h); + Curl_node_uremove(le, (void *)h); --h->size; break; } @@ -158,18 +158,16 @@ Curl_hash_add(struct Curl_hash *h, void *key, size_t key_len, void *p) */ int Curl_hash_delete(struct Curl_hash *h, void *key, size_t key_len) { - struct Curl_llist_element *le; - struct Curl_llist *l; - DEBUGASSERT(h); DEBUGASSERT(h->slots); if(h->table) { - l = FETCH_LIST(h, key, key_len); + struct Curl_llist_node *le; + struct Curl_llist *l = FETCH_LIST(h, key, key_len); - for(le = l->head; le; le = le->next) { - struct Curl_hash_element *he = le->ptr; + for(le = Curl_llist_head(l); le; le = Curl_node_next(le)) { + struct Curl_hash_element *he = Curl_node_elem(le); if(h->comp_func(he->key, he->key_len, key, key_len)) { - Curl_llist_remove(l, le, (void *) h); + Curl_node_uremove(le, (void *) h); --h->size; return 0; } @@ -185,15 +183,14 @@ int Curl_hash_delete(struct Curl_hash *h, void *key, size_t key_len) void * Curl_hash_pick(struct Curl_hash *h, void *key, size_t key_len) { - struct Curl_llist_element *le; - struct Curl_llist *l; - DEBUGASSERT(h); if(h->table) { + struct Curl_llist_node *le; + struct Curl_llist *l; DEBUGASSERT(h->slots); l = FETCH_LIST(h, key, key_len); - for(le = l->head; le; le = le->next) { - struct Curl_hash_element *he = le->ptr; + for(le = Curl_llist_head(l); le; le = Curl_node_next(le)) { + struct Curl_hash_element *he = Curl_node_elem(le); if(h->comp_func(he->key, he->key_len, key, key_len)) { return he->ptr; } @@ -239,23 +236,21 @@ void Curl_hash_clean_with_criterium(struct Curl_hash *h, void *user, int (*comp)(void *, void *)) { - struct Curl_llist_element *le; - struct Curl_llist_element *lnext; - struct Curl_llist *list; size_t i; if(!h || !h->table) return; for(i = 0; i < h->slots; ++i) { - list = &h->table[i]; - le = list->head; /* get first list entry */ + struct Curl_llist *list = &h->table[i]; + struct Curl_llist_node *le = + Curl_llist_head(list); /* get first list entry */ while(le) { - struct Curl_hash_element *he = le->ptr; - lnext = le->next; + struct Curl_hash_element *he = Curl_node_elem(le); + struct Curl_llist_node *lnext = Curl_node_next(le); /* ask the callback function if we shall remove this entry or not */ if(!comp || comp(user, he->ptr)) { - Curl_llist_remove(list, le, (void *) h); + Curl_node_uremove(le, (void *) h); --h->size; /* one less entry in the hash now */ } le = lnext; @@ -305,14 +300,14 @@ Curl_hash_next_element(struct Curl_hash_iterator *iter) /* Get the next element in the current list, if any */ if(iter->current_element) - iter->current_element = iter->current_element->next; + iter->current_element = Curl_node_next(iter->current_element); /* If we have reached the end of the list, find the next one */ if(!iter->current_element) { size_t i; for(i = iter->slot_index; i < h->slots; i++) { - if(h->table[i].head) { - iter->current_element = h->table[i].head; + if(Curl_llist_head(&h->table[i])) { + iter->current_element = Curl_llist_head(&h->table[i]); iter->slot_index = i + 1; break; } @@ -320,7 +315,7 @@ Curl_hash_next_element(struct Curl_hash_iterator *iter) } if(iter->current_element) { - struct Curl_hash_element *he = iter->current_element->ptr; + struct Curl_hash_element *he = Curl_node_elem(iter->current_element); return he; } return NULL; diff --git a/lib/hash.h b/lib/hash.h index 1cf787525b..b0bc29be39 100644 --- a/lib/hash.h +++ b/lib/hash.h @@ -61,7 +61,7 @@ struct Curl_hash { typedef void (*Curl_hash_elem_dtor)(void *key, size_t key_len, void *p); struct Curl_hash_element { - struct Curl_llist_element list; + struct Curl_llist_node list; void *ptr; Curl_hash_elem_dtor dtor; size_t key_len; @@ -71,7 +71,7 @@ struct Curl_hash_element { struct Curl_hash_iterator { struct Curl_hash *hash; size_t slot_index; - struct Curl_llist_element *current_element; + struct Curl_llist_node *current_element; }; void Curl_hash_init(struct Curl_hash *h, diff --git a/lib/headers.c b/lib/headers.c index 59ac422258..7c60c07985 100644 --- a/lib/headers.c +++ b/lib/headers.c @@ -42,7 +42,7 @@ static void copy_header_external(struct Curl_header_store *hs, size_t index, size_t amount, - struct Curl_llist_element *e, + struct Curl_llist_node *e, struct curl_header *hout) { struct curl_header *h = hout; @@ -66,8 +66,8 @@ CURLHcode curl_easy_header(CURL *easy, int request, struct curl_header **hout) { - struct Curl_llist_element *e; - struct Curl_llist_element *e_pick = NULL; + struct Curl_llist_node *e; + struct Curl_llist_node *e_pick = NULL; struct Curl_easy *data = easy; size_t match = 0; size_t amount = 0; @@ -85,8 +85,8 @@ CURLHcode curl_easy_header(CURL *easy, request = data->state.requests; /* we need a first round to count amount of this header */ - for(e = data->state.httphdrs.head; e; e = e->next) { - hs = e->ptr; + for(e = Curl_llist_head(&data->state.httphdrs); e; e = Curl_node_next(e)) { + hs = Curl_node_elem(e); if(strcasecompare(hs->name, name) && (hs->type & type) && (hs->request == request)) { @@ -104,8 +104,8 @@ CURLHcode curl_easy_header(CURL *easy, /* if the last or only occurrence is what's asked for, then we know it */ hs = pick; else { - for(e = data->state.httphdrs.head; e; e = e->next) { - hs = e->ptr; + for(e = Curl_llist_head(&data->state.httphdrs); e; e = Curl_node_next(e)) { + hs = Curl_node_elem(e); if(strcasecompare(hs->name, name) && (hs->type & type) && (hs->request == request) && @@ -131,8 +131,8 @@ struct curl_header *curl_easy_nextheader(CURL *easy, struct curl_header *prev) { struct Curl_easy *data = easy; - struct Curl_llist_element *pick; - struct Curl_llist_element *e; + struct Curl_llist_node *pick; + struct Curl_llist_node *e; struct Curl_header_store *hs; size_t amount = 0; size_t index = 0; @@ -147,18 +147,18 @@ struct curl_header *curl_easy_nextheader(CURL *easy, if(!pick) /* something is wrong */ return NULL; - pick = pick->next; + pick = Curl_node_next(pick); } else - pick = data->state.httphdrs.head; + pick = Curl_llist_head(&data->state.httphdrs); if(pick) { /* make sure it is the next header of the desired type */ do { - hs = pick->ptr; + hs = Curl_node_elem(pick); if((hs->type & type) && (hs->request == request)) break; - pick = pick->next; + pick = Curl_node_next(pick); } while(pick); } @@ -166,12 +166,12 @@ struct curl_header *curl_easy_nextheader(CURL *easy, /* no more headers available */ return NULL; - hs = pick->ptr; + hs = Curl_node_elem(pick); /* count number of occurrences of this name within the mask and figure out the index for the currently selected entry */ - for(e = data->state.httphdrs.head; e; e = e->next) { - struct Curl_header_store *check = e->ptr; + for(e = Curl_llist_head(&data->state.httphdrs); e; e = Curl_node_next(e)) { + struct Curl_header_store *check = Curl_node_elem(e); if(strcasecompare(hs->name, check->name) && (check->request == request) && (check->type & type)) @@ -247,7 +247,7 @@ static CURLcode unfold_value(struct Curl_easy *data, const char *value, /* since this header block might move in the realloc below, it needs to first be unlinked from the list and then re-added again after the realloc */ - Curl_llist_remove(&data->state.httphdrs, &hs->node, NULL); + Curl_node_remove(&hs->node); /* new size = struct + new value length + old name+value length */ newhs = Curl_saferealloc(hs, sizeof(*hs) + vlen + oalloc + 1); @@ -405,12 +405,12 @@ CURLcode Curl_headers_init(struct Curl_easy *data) */ CURLcode Curl_headers_cleanup(struct Curl_easy *data) { - struct Curl_llist_element *e; - struct Curl_llist_element *n; + struct Curl_llist_node *e; + struct Curl_llist_node *n; - for(e = data->state.httphdrs.head; e; e = n) { - struct Curl_header_store *hs = e->ptr; - n = e->next; + for(e = Curl_llist_head(&data->state.httphdrs); e; e = n) { + struct Curl_header_store *hs = Curl_node_elem(e); + n = Curl_node_next(e); free(hs); } headers_reset(data); diff --git a/lib/headers.h b/lib/headers.h index d9813388c5..e11fe9804e 100644 --- a/lib/headers.h +++ b/lib/headers.h @@ -28,7 +28,7 @@ #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_HEADERS_API) struct Curl_header_store { - struct Curl_llist_element node; + struct Curl_llist_node node; char *name; /* points into 'buffer' */ char *value; /* points into 'buffer */ int request; /* 0 is the first request, then 1.. 2.. */ diff --git a/lib/hsts.c b/lib/hsts.c index 8cd77ae3cf..a5c216f6de 100644 --- a/lib/hsts.c +++ b/lib/hsts.c @@ -94,11 +94,11 @@ void Curl_hsts_cleanup(struct hsts **hp) { struct hsts *h = *hp; if(h) { - struct Curl_llist_element *e; - struct Curl_llist_element *n; - for(e = h->list.head; e; e = n) { - struct stsentry *sts = e->ptr; - n = e->next; + struct Curl_llist_node *e; + struct Curl_llist_node *n; + for(e = Curl_llist_head(&h->list); e; e = n) { + struct stsentry *sts = Curl_node_elem(e); + n = Curl_node_next(e); hsts_free(sts); } free(h->filename); @@ -215,7 +215,7 @@ CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname, /* remove the entry if present verbatim (without subdomain match) */ sts = Curl_hsts(h, hostname, FALSE); if(sts) { - Curl_llist_remove(&h->list, &sts->node, NULL); + Curl_node_remove(&sts->node); hsts_free(sts); } return CURLE_OK; @@ -253,8 +253,8 @@ struct stsentry *Curl_hsts(struct hsts *h, const char *hostname, char buffer[MAX_HSTS_HOSTLEN + 1]; time_t now = time(NULL); size_t hlen = strlen(hostname); - struct Curl_llist_element *e; - struct Curl_llist_element *n; + struct Curl_llist_node *e; + struct Curl_llist_node *n; if((hlen > MAX_HSTS_HOSTLEN) || !hlen) return NULL; @@ -265,12 +265,12 @@ struct stsentry *Curl_hsts(struct hsts *h, const char *hostname, buffer[hlen] = 0; hostname = buffer; - for(e = h->list.head; e; e = n) { - struct stsentry *sts = e->ptr; - n = e->next; + for(e = Curl_llist_head(&h->list); e; e = n) { + struct stsentry *sts = Curl_node_elem(e); + n = Curl_node_next(e); if(sts->expires <= now) { /* remove expired entries */ - Curl_llist_remove(&h->list, &sts->node, NULL); + Curl_node_remove(&sts->node); hsts_free(sts); continue; } @@ -353,8 +353,8 @@ static CURLcode hsts_out(struct stsentry *sts, FILE *fp) CURLcode Curl_hsts_save(struct Curl_easy *data, struct hsts *h, const char *file) { - struct Curl_llist_element *e; - struct Curl_llist_element *n; + struct Curl_llist_node *e; + struct Curl_llist_node *n; CURLcode result = CURLE_OK; FILE *out; char *tempstore = NULL; @@ -376,9 +376,9 @@ CURLcode Curl_hsts_save(struct Curl_easy *data, struct hsts *h, fputs("# Your HSTS cache. https://curl.se/docs/hsts.html\n" "# This file was generated by libcurl! Edit at your own risk.\n", out); - for(e = h->list.head; e; e = n) { - struct stsentry *sts = e->ptr; - n = e->next; + for(e = Curl_llist_head(&h->list); e; e = n) { + struct stsentry *sts = Curl_node_elem(e); + n = Curl_node_next(e); result = hsts_out(sts, out); if(result) break; @@ -395,12 +395,12 @@ skipsave: if(data->set.hsts_write) { /* if there is a write callback */ struct curl_index i; /* count */ - i.total = h->list.size; + i.total = Curl_llist_count(&h->list); i.index = 0; - for(e = h->list.head; e; e = n) { - struct stsentry *sts = e->ptr; + for(e = Curl_llist_head(&h->list); e; e = n) { + struct stsentry *sts = Curl_node_elem(e); bool stop; - n = e->next; + n = Curl_node_next(e); result = hsts_push(data, &i, sts, &stop); if(result || stop) break; diff --git a/lib/hsts.h b/lib/hsts.h index 21e53a3427..1c544f97bd 100644 --- a/lib/hsts.h +++ b/lib/hsts.h @@ -34,7 +34,7 @@ extern time_t deltatime; #endif struct stsentry { - struct Curl_llist_element node; + struct Curl_llist_node node; const char *host; bool includeSubDomains; curl_off_t expires; /* the timestamp of this entry's expiry */ diff --git a/lib/http.c b/lib/http.c index 309843a467..9b1fc71630 100644 --- a/lib/http.c +++ b/lib/http.c @@ -3118,7 +3118,7 @@ CURLcode Curl_http_header(struct Curl_easy *data, #ifdef DEBUGBUILD else infof(data, "Parsed STS header fine (%zu entries)", - data->hsts->list.size); + Curl_llist_count(&data->hsts->list)); #endif } #endif diff --git a/lib/llist.c b/lib/llist.c index 716f0cd576..84bcc9f5b6 100644 --- a/lib/llist.c +++ b/lib/llist.c @@ -32,16 +32,34 @@ /* this must be the last include file */ #include "memdebug.h" +#define LLISTINIT 0x100cc001 /* random pattern */ +#define NODEINIT 0x12344321 /* random pattern */ +#define NODEREM 0x54321012 /* random pattern */ + + +#ifdef DEBUGBUILD +#define VERIFYNODE(x) verifynode(x) +static struct Curl_llist_node *verifynode(struct Curl_llist_node *n) +{ + DEBUGASSERT(!n || (n->_init == NODEINIT)); + return n; +} +#else +#define VERIFYNODE(x) x +#endif /* * @unittest: 1300 */ void Curl_llist_init(struct Curl_llist *l, Curl_llist_dtor dtor) { - l->size = 0; - l->dtor = dtor; - l->head = NULL; - l->tail = NULL; + l->_size = 0; + l->_dtor = dtor; + l->_head = NULL; + l->_tail = NULL; +#ifdef DEBUGBUILD + l->_init = LLISTINIT; +#endif } /* @@ -56,36 +74,45 @@ Curl_llist_init(struct Curl_llist *l, Curl_llist_dtor dtor) * @unittest: 1300 */ void -Curl_llist_insert_next(struct Curl_llist *list, struct Curl_llist_element *e, +Curl_llist_insert_next(struct Curl_llist *list, + struct Curl_llist_node *e, /* may be NULL */ const void *p, - struct Curl_llist_element *ne) + struct Curl_llist_node *ne) { - ne->ptr = (void *) p; - if(list->size == 0) { - list->head = ne; - list->head->prev = NULL; - list->head->next = NULL; - list->tail = ne; + DEBUGASSERT(list); + DEBUGASSERT(list->_init == LLISTINIT); + DEBUGASSERT(ne); + +#ifdef DEBUGBUILD + ne->_init = NODEINIT; +#endif + ne->_ptr = (void *) p; + ne->_list = list; + if(list->_size == 0) { + list->_head = ne; + list->_head->_prev = NULL; + list->_head->_next = NULL; + list->_tail = ne; } else { /* if 'e' is NULL here, we insert the new element first in the list */ - ne->next = e?e->next:list->head; - ne->prev = e; + ne->_next = e?e->_next:list->_head; + ne->_prev = e; if(!e) { - list->head->prev = ne; - list->head = ne; + list->_head->_prev = ne; + list->_head = ne; } - else if(e->next) { - e->next->prev = ne; + else if(e->_next) { + e->_next->_prev = ne; } else { - list->tail = ne; + list->_tail = ne; } if(e) - e->next = ne; + e->_next = ne; } - ++list->size; + ++list->_size; } /* @@ -99,64 +126,131 @@ Curl_llist_insert_next(struct Curl_llist *list, struct Curl_llist_element *e, */ void Curl_llist_append(struct Curl_llist *list, const void *p, - struct Curl_llist_element *ne) + struct Curl_llist_node *ne) { - Curl_llist_insert_next(list, list->tail, p, ne); + DEBUGASSERT(list); + DEBUGASSERT(list->_init == LLISTINIT); + DEBUGASSERT(ne); + Curl_llist_insert_next(list, list->_tail, p, ne); } /* * @unittest: 1300 */ void -Curl_llist_remove(struct Curl_llist *list, struct Curl_llist_element *e, - void *user) +Curl_node_uremove(struct Curl_llist_node *e, void *user) { void *ptr; - if(!e || list->size == 0) + struct Curl_llist *list; + if(!e) return; - if(e == list->head) { - list->head = e->next; + list = e->_list; + DEBUGASSERT(list); + DEBUGASSERT(list->_init == LLISTINIT); + DEBUGASSERT(list->_size); + DEBUGASSERT(e->_init == NODEINIT); + if(e == list->_head) { + list->_head = e->_next; - if(!list->head) - list->tail = NULL; + if(!list->_head) + list->_tail = NULL; else - e->next->prev = NULL; + e->_next->_prev = NULL; } else { - if(e->prev) - e->prev->next = e->next; + if(e->_prev) + e->_prev->_next = e->_next; - if(!e->next) - list->tail = e->prev; + if(!e->_next) + list->_tail = e->_prev; else - e->next->prev = e->prev; + e->_next->_prev = e->_prev; } - ptr = e->ptr; + ptr = e->_ptr; - e->ptr = NULL; - e->prev = NULL; - e->next = NULL; + e->_ptr = NULL; + e->_prev = NULL; + e->_next = NULL; +#ifdef DEBUGBUILD + e->_init = NODEREM; /* specific pattern on remove - not zero */ +#endif - --list->size; + --list->_size; /* call the dtor() last for when it actually frees the 'e' memory itself */ - if(list->dtor) - list->dtor(user, ptr); + if(list->_dtor) + list->_dtor(user, ptr); +} + +void Curl_node_remove(struct Curl_llist_node *e) +{ + Curl_node_uremove(e, NULL); } void Curl_llist_destroy(struct Curl_llist *list, void *user) { if(list) { - while(list->size > 0) - Curl_llist_remove(list, list->tail, user); + DEBUGASSERT(list->_init == LLISTINIT); + while(list->_size > 0) + Curl_node_uremove(list->_tail, user); } } -size_t -Curl_llist_count(struct Curl_llist *list) +/* Curl_llist_head() returns the first 'struct Curl_llist_node *', which + might be NULL */ +struct Curl_llist_node *Curl_llist_head(struct Curl_llist *list) +{ + DEBUGASSERT(list); + DEBUGASSERT(list->_init == LLISTINIT); + return VERIFYNODE(list->_head); +} + +/* Curl_llist_tail() returns the last 'struct Curl_llist_node *', which + might be NULL */ +struct Curl_llist_node *Curl_llist_tail(struct Curl_llist *list) { - return list->size; + DEBUGASSERT(list); + DEBUGASSERT(list->_init == LLISTINIT); + return VERIFYNODE(list->_tail); } + +/* Curl_llist_count() returns a size_t the number of nodes in the list */ +size_t Curl_llist_count(struct Curl_llist *list) +{ + DEBUGASSERT(list); + DEBUGASSERT(list->_init == LLISTINIT); + return list->_size; +} + +/* Curl_node_elem() returns the custom data from a Curl_llist_node */ +void *Curl_node_elem(struct Curl_llist_node *n) +{ + DEBUGASSERT(n); + DEBUGASSERT(n->_init == NODEINIT); + return n->_ptr; +} + +/* Curl_node_next() returns the next element in a list from a given + Curl_llist_node */ +struct Curl_llist_node *Curl_node_next(struct Curl_llist_node *n) +{ + DEBUGASSERT(n); + DEBUGASSERT(n->_init == NODEINIT); + return VERIFYNODE(n->_next); +} + +#ifdef UNITTEST + +/* Curl_node_prev() returns the previous element in a list from a given + Curl_llist_node */ +struct Curl_llist_node *Curl_node_prev(struct Curl_llist_node *n) +{ + DEBUGASSERT(n); + DEBUGASSERT(n->_init == NODEINIT); + return VERIFYNODE(n->_prev); +} + +#endif diff --git a/lib/llist.h b/lib/llist.h index d75582fa97..f12d71e00c 100644 --- a/lib/llist.h +++ b/lib/llist.h @@ -27,28 +27,60 @@ #include "curl_setup.h" #include -typedef void (*Curl_llist_dtor)(void *, void *); +typedef void (*Curl_llist_dtor)(void *user, void *elem); -struct Curl_llist_element { - void *ptr; - struct Curl_llist_element *prev; - struct Curl_llist_element *next; -}; +/* none of these struct members should be referenced directly, use the + dedicated functions */ struct Curl_llist { - struct Curl_llist_element *head; - struct Curl_llist_element *tail; - Curl_llist_dtor dtor; - size_t size; + struct Curl_llist_node *_head; + struct Curl_llist_node *_tail; + Curl_llist_dtor _dtor; + size_t _size; +#ifdef DEBUGBUILD + int _init; /* detect API usage mistakes */ +#endif +}; + +struct Curl_llist_node { + struct Curl_llist *_list; /* the list where this belongs */ + void *_ptr; + struct Curl_llist_node *_prev; + struct Curl_llist_node *_next; +#ifdef DEBUGBUILD + int _init; /* detect API usage mistakes */ +#endif }; void Curl_llist_init(struct Curl_llist *, Curl_llist_dtor); -void Curl_llist_insert_next(struct Curl_llist *, struct Curl_llist_element *, - const void *, struct Curl_llist_element *node); +void Curl_llist_insert_next(struct Curl_llist *, struct Curl_llist_node *, + const void *, struct Curl_llist_node *node); void Curl_llist_append(struct Curl_llist *, - const void *, struct Curl_llist_element *node); -void Curl_llist_remove(struct Curl_llist *, struct Curl_llist_element *, - void *); -size_t Curl_llist_count(struct Curl_llist *); + const void *, struct Curl_llist_node *node); +void Curl_node_uremove(struct Curl_llist_node *, void *); +void Curl_node_remove(struct Curl_llist_node *); void Curl_llist_destroy(struct Curl_llist *, void *); + +/* Curl_llist_head() returns the first 'struct Curl_llist_node *', which + might be NULL */ +struct Curl_llist_node *Curl_llist_head(struct Curl_llist *list); + +/* Curl_llist_tail() returns the last 'struct Curl_llist_node *', which + might be NULL */ +struct Curl_llist_node *Curl_llist_tail(struct Curl_llist *list); + +/* Curl_llist_count() returns a size_t the number of nodes in the list */ +size_t Curl_llist_count(struct Curl_llist *list); + +/* Curl_node_elem() returns the custom data from a Curl_llist_node */ +void *Curl_node_elem(struct Curl_llist_node *n); + +/* Curl_node_next() returns the next element in a list from a given + Curl_llist_node */ +struct Curl_llist_node *Curl_node_next(struct Curl_llist_node *n); + +/* Curl_node_prev() returns the previous element in a list from a given + Curl_llist_node */ +struct Curl_llist_node *Curl_node_prev(struct Curl_llist_node *n); + #endif /* HEADER_CURL_LLIST_H */ diff --git a/lib/multi.c b/lib/multi.c index 21fc6c0e68..e6b323f1ab 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -467,21 +467,6 @@ static void multi_warn_debug(struct Curl_multi *multi, struct Curl_easy *data) #define multi_warn_debug(x,y) Curl_nop_stmt #endif -static void link_easy(struct Curl_multi *multi, - struct Curl_easy *data) -{ - /* add the easy handle to the process list */ - Curl_llist_append(&multi->process, data, &data->multi_queue); -} - -/* unlink the given easy handle from the process list */ -static void unlink_easy(struct Curl_multi *multi, - struct Curl_easy *data) -{ - Curl_llist_remove(&multi->process, &data->multi_queue, NULL); -} - - CURLMcode curl_multi_add_handle(struct Curl_multi *multi, struct Curl_easy *data) { @@ -557,8 +542,10 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi, memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall)); rc = Curl_update_timer(multi); - if(rc) + if(rc) { + data->multi = NULL; /* not anymore */ return rc; + } /* set the easy handle */ multistate(data, MSTATE_INIT); @@ -586,7 +573,8 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi, data->psl = &multi->psl; #endif - link_easy(multi, data); + /* add the easy handle to the process list */ + Curl_llist_append(&multi->process, data, &data->multi_queue); /* increase the node-counter */ multi->num_easy++; @@ -706,7 +694,7 @@ static CURLcode multi_done(struct Curl_easy *data, CONNCACHE_UNLOCK(data); DEBUGF(infof(data, "Connection still in use %zu, " "no more multi_done now!", - conn->easyq.size)); + Curl_llist_count(&conn->easyq))); return CURLE_OK; } @@ -804,7 +792,7 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi, { struct Curl_easy *easy = data; bool premature; - struct Curl_llist_element *e; + struct Curl_llist_node *e; CURLMcode rc; /* First, make some basic checks that the CURLM handle is a good handle */ @@ -812,7 +800,7 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi, return CURLM_BAD_HANDLE; /* Verify that we got a somewhat good easy handle too */ - if(!GOOD_EASY_HANDLE(data)) + if(!GOOD_EASY_HANDLE(data) || !multi->num_easy) return CURLM_BAD_EASY_HANDLE; /* Prevent users from trying to remove same easy handle more than once */ @@ -858,15 +846,8 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi, called. Do it after multi_done() in case that sets another time! */ Curl_expire_clear(data); - if(data->multi_queue.ptr) { - /* the handle is in a list, remove it from the right one */ - if(data->mstate == MSTATE_PENDING) - Curl_llist_remove(&multi->pending, &data->multi_queue, NULL); - else if(data->mstate == MSTATE_MSGSENT) - Curl_llist_remove(&multi->msgsent, &data->multi_queue, NULL); - else - Curl_llist_remove(&multi->process, &data->multi_queue, NULL); - } + /* the handle is in a list, remove it from whichever it is */ + Curl_node_remove(&data->multi_queue); if(data->dns.hostcachetype == HCACHE_MULTI) { /* stop using the multi handle's DNS cache, *after* the possible @@ -927,11 +908,11 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi, /* make sure there is no pending message in the queue sent from this easy handle */ - for(e = multi->msglist.head; e; e = e->next) { - struct Curl_message *msg = e->ptr; + for(e = Curl_llist_head(&multi->msglist); e; e = Curl_node_next(e)) { + struct Curl_message *msg = Curl_node_elem(e); if(msg->extmsg.easy_handle == easy) { - Curl_llist_remove(&multi->msglist, e, NULL); + Curl_node_remove(e); /* there can only be one from this specific handle */ break; } @@ -966,7 +947,7 @@ void Curl_detach_connection(struct Curl_easy *data) struct connectdata *conn = data->conn; if(conn) { Curl_conn_ev_data_detach(conn, data); - Curl_llist_remove(&conn->easyq, &data->conn_queue, NULL); + Curl_node_remove(&data->conn_queue); } data->conn = NULL; } @@ -1181,7 +1162,7 @@ CURLMcode curl_multi_fdset(struct Curl_multi *multi, and then we must make sure that is done. */ int this_max_fd = -1; struct easy_pollset ps; - struct Curl_llist_element *e; + struct Curl_llist_node *e; (void)exc_fd_set; /* not used */ if(!GOOD_MULTI_HANDLE(multi)) @@ -1191,8 +1172,8 @@ CURLMcode curl_multi_fdset(struct Curl_multi *multi, return CURLM_RECURSIVE_API_CALL; memset(&ps, 0, sizeof(ps)); - for(e = multi->process.head; e; e = e->next) { - struct Curl_easy *data = e->ptr; + for(e = Curl_llist_head(&multi->process); e; e = Curl_node_next(e)) { + struct Curl_easy *data = Curl_node_elem(e); unsigned int i; multi_getsock(data, &ps); @@ -1223,7 +1204,7 @@ CURLMcode curl_multi_waitfds(struct Curl_multi *multi, struct curl_waitfds cwfds; struct easy_pollset ps; CURLMcode result = CURLM_OK; - struct Curl_llist_element *e; + struct Curl_llist_node *e; if(!ufds) return CURLM_BAD_FUNCTION_ARGUMENT; @@ -1236,8 +1217,8 @@ CURLMcode curl_multi_waitfds(struct Curl_multi *multi, Curl_waitfds_init(&cwfds, ufds, size); memset(&ps, 0, sizeof(ps)); - for(e = multi->process.head; e; e = e->next) { - struct Curl_easy *data = e->ptr; + for(e = Curl_llist_head(&multi->process); e; e = Curl_node_next(e)) { + struct Curl_easy *data = Curl_node_elem(e); multi_getsock(data, &ps); if(Curl_waitfds_add_ps(&cwfds, &ps)) { result = CURLM_OUT_OF_MEMORY; @@ -1290,7 +1271,7 @@ static CURLMcode multi_wait(struct Curl_multi *multi, struct curl_pollfds cpfds; unsigned int curl_nfds = 0; /* how many pfds are for curl transfers */ CURLMcode result = CURLM_OK; - struct Curl_llist_element *e; + struct Curl_llist_node *e; #ifdef USE_WINSOCK WSANETWORKEVENTS wsa_events; @@ -1313,8 +1294,8 @@ static CURLMcode multi_wait(struct Curl_multi *multi, memset(&ps, 0, sizeof(ps)); /* Add the curl handles to our pollfds first */ - for(e = multi->process.head; e; e = e->next) { - struct Curl_easy *data = e->ptr; + for(e = Curl_llist_head(&multi->process); e; e = Curl_node_next(e)) { + struct Curl_easy *data = Curl_node_elem(e); multi_getsock(data, &ps); if(Curl_pollfds_add_ps(&cpfds, &ps)) { @@ -1453,8 +1434,9 @@ static CURLMcode multi_wait(struct Curl_multi *multi, /* Count up all our own sockets that had activity, and remove them from the event. */ if(curl_nfds) { - for(e = multi->process.head; e && !result; e = e->next) { - struct Curl_easy *data = e->ptr; + for(e = Curl_llist_head(&multi->process); e && !result; + e = Curl_node_next(e)) { + struct Curl_easy *data = Curl_node_elem(e); multi_getsock(data, &ps); for(i = 0; i < ps.num; i++) { @@ -1948,7 +1930,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, state and wait for an available connection. */ multistate(data, MSTATE_PENDING); /* unlink from process list */ - unlink_easy(multi, data); + Curl_node_remove(&data->multi_queue); /* add handle to pending list */ Curl_llist_append(&multi->pending, data, &data->multi_queue); result = CURLE_OK; @@ -2661,9 +2643,9 @@ statemachine_end: } multistate(data, MSTATE_MSGSENT); - /* unlink from the main list */ - unlink_easy(multi, data); - /* add this handle to the list of msgsent handles */ + /* unlink from the process list */ + Curl_node_remove(&data->multi_queue); + /* add this handle msgsent list */ Curl_llist_append(&multi->msgsent, data, &data->multi_queue); return CURLM_OK; } @@ -2679,8 +2661,8 @@ CURLMcode curl_multi_perform(struct Curl_multi *multi, int *running_handles) CURLMcode returncode = CURLM_OK; struct Curl_tree *t; struct curltime now = Curl_now(); - struct Curl_llist_element *e; - struct Curl_llist_element *n = NULL; + struct Curl_llist_node *e; + struct Curl_llist_node *n = NULL; SIGPIPE_VARIABLE(pipe_st); if(!GOOD_MULTI_HANDLE(multi)) @@ -2690,15 +2672,15 @@ CURLMcode curl_multi_perform(struct Curl_multi *multi, int *running_handles) return CURLM_RECURSIVE_API_CALL; sigpipe_init(&pipe_st); - for(e = multi->process.head; e; e = n) { - struct Curl_easy *data = e->ptr; + for(e = Curl_llist_head(&multi->process); e; e = n) { + struct Curl_easy *data = Curl_node_elem(e); CURLMcode result; /* Do the loop and only alter the signal ignore state if the next handle has a different NO_SIGNAL state than the previous */ /* the current node might be unlinked in multi_runsingle(), get the next pointer now */ - n = e->next; + n = Curl_node_next(e); if(data != multi->conn_cache.closure_handle) { /* connection cache handle is processed below */ @@ -2755,14 +2737,14 @@ CURLMcode curl_multi_perform(struct Curl_multi *multi, int *running_handles) the process list */ static void unlink_all_msgsent_handles(struct Curl_multi *multi) { - struct Curl_llist_element *e; - for(e = multi->msgsent.head; e; e = e->next) { - struct Curl_easy *data = e->ptr; + struct Curl_llist_node *e; + for(e = Curl_llist_head(&multi->msgsent); e; e = Curl_node_next(e)) { + struct Curl_easy *data = Curl_node_elem(e); if(data) { DEBUGASSERT(data->mstate == MSTATE_MSGSENT); - Curl_llist_remove(&multi->msgsent, &data->multi_queue, NULL); + Curl_node_remove(&data->multi_queue); /* put it into the process list */ - link_easy(multi, data); + Curl_llist_append(&multi->process, data, &data->multi_queue); } } } @@ -2770,8 +2752,8 @@ static void unlink_all_msgsent_handles(struct Curl_multi *multi) CURLMcode curl_multi_cleanup(struct Curl_multi *multi) { if(GOOD_MULTI_HANDLE(multi)) { - struct Curl_llist_element *e; - struct Curl_llist_element *n; + struct Curl_llist_node *e; + struct Curl_llist_node *n; if(multi->in_callback) return CURLM_RECURSIVE_API_CALL; @@ -2783,13 +2765,13 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi) process_pending_handles(multi); /* First remove all remaining easy handles */ - for(e = multi->process.head; e; e = n) { - struct Curl_easy *data = e->ptr; + for(e = Curl_llist_head(&multi->process); e; e = n) { + struct Curl_easy *data = Curl_node_elem(e); if(!GOOD_EASY_HANDLE(data)) return CURLM_BAD_HANDLE; - n = e->next; + n = Curl_node_next(e); if(!data->state.done && data->conn) /* if DONE was never called for this handle */ (void)multi_done(data, CURLE_OK, TRUE); @@ -2858,15 +2840,15 @@ CURLMsg *curl_multi_info_read(struct Curl_multi *multi, int *msgs_in_queue) !multi->in_callback && Curl_llist_count(&multi->msglist)) { /* there is one or more messages in the list */ - struct Curl_llist_element *e; + struct Curl_llist_node *e; /* extract the head of the list to return */ - e = multi->msglist.head; + e = Curl_llist_head(&multi->msglist); - msg = e->ptr; + msg = Curl_node_elem(e); /* remove the extracted entry */ - Curl_llist_remove(&multi->msglist, e, NULL); + Curl_node_remove(e); *msgs_in_queue = curlx_uztosi(Curl_llist_count(&multi->msglist)); @@ -3110,26 +3092,24 @@ static CURLMcode add_next_timeout(struct curltime now, { struct curltime *tv = &d->state.expiretime; struct Curl_llist *list = &d->state.timeoutlist; - struct Curl_llist_element *e; - struct time_node *node = NULL; + struct Curl_llist_node *e; /* move over the timeout list for this specific handle and remove all timeouts that are now passed tense and store the next pending timeout in *tv */ - for(e = list->head; e;) { - struct Curl_llist_element *n = e->next; - timediff_t diff; - node = (struct time_node *)e->ptr; - diff = Curl_timediff_us(node->time, now); + for(e = Curl_llist_head(list); e;) { + struct Curl_llist_node *n = Curl_node_next(e); + struct time_node *node = Curl_node_elem(e); + timediff_t diff = Curl_timediff_us(node->time, now); if(diff <= 0) /* remove outdated entry */ - Curl_llist_remove(list, e, NULL); + Curl_node_remove(e); else /* the list is sorted so get out on the first mismatch */ break; e = n; } - e = list->head; + e = Curl_llist_head(list); if(!e) { /* clear the expire times within the handles that we remove from the splay tree */ @@ -3137,6 +3117,7 @@ static CURLMcode add_next_timeout(struct curltime now, tv->tv_usec = 0; } else { + struct time_node *node = Curl_node_elem(e); /* copy the first entry to 'tv' */ memcpy(tv, &node->time, sizeof(*tv)); @@ -3162,15 +3143,16 @@ static CURLMcode multi_socket(struct Curl_multi *multi, SIGPIPE_VARIABLE(pipe_st); if(checkall) { - struct Curl_llist_element *e; + struct Curl_llist_node *e; /* *perform() deals with running_handles on its own */ result = curl_multi_perform(multi, running_handles); /* walk through each easy handle and do the socket state change magic and callbacks */ if(result != CURLM_BAD_HANDLE) { - for(e = multi->process.head; e && !result; e = e->next) { - result = singlesocket(multi, e->ptr); + for(e = Curl_llist_head(&multi->process); e && !result; + e = Curl_node_next(e)) { + result = singlesocket(multi, Curl_node_elem(e)); } } @@ -3499,13 +3481,13 @@ CURLMcode Curl_update_timer(struct Curl_multi *multi) static void multi_deltimeout(struct Curl_easy *data, expire_id eid) { - struct Curl_llist_element *e; + struct Curl_llist_node *e; struct Curl_llist *timeoutlist = &data->state.timeoutlist; /* find and remove the specific node from the list */ - for(e = timeoutlist->head; e; e = e->next) { - struct time_node *n = (struct time_node *)e->ptr; + for(e = Curl_llist_head(timeoutlist); e; e = Curl_node_next(e)) { + struct time_node *n = Curl_node_elem(e); if(n->eid == eid) { - Curl_llist_remove(timeoutlist, e, NULL); + Curl_node_remove(e); return; } } @@ -3523,9 +3505,9 @@ multi_addtimeout(struct Curl_easy *data, struct curltime *stamp, expire_id eid) { - struct Curl_llist_element *e; + struct Curl_llist_node *e; struct time_node *node; - struct Curl_llist_element *prev = NULL; + struct Curl_llist_node *prev = NULL; size_t n; struct Curl_llist *timeoutlist = &data->state.timeoutlist; @@ -3538,8 +3520,8 @@ multi_addtimeout(struct Curl_easy *data, n = Curl_llist_count(timeoutlist); if(n) { /* find the correct spot in the list */ - for(e = timeoutlist->head; e; e = e->next) { - struct time_node *check = (struct time_node *)e->ptr; + for(e = Curl_llist_head(timeoutlist); e; e = Curl_node_next(e)) { + struct time_node *check = Curl_node_elem(e); timediff_t diff = Curl_timediff(check->time, node->time); if(diff > 0) break; @@ -3661,10 +3643,8 @@ void Curl_expire_clear(struct Curl_easy *data) if(rc) infof(data, "Internal error clearing splay node = %d", rc); - /* flush the timeout list too */ - while(list->size > 0) { - Curl_llist_remove(list, list->tail, NULL); - } + /* clear the timeout list too */ + Curl_llist_destroy(list, NULL); #ifdef DEBUGBUILD infof(data, "Expire cleared"); @@ -3726,10 +3706,10 @@ static void move_pending_to_connect(struct Curl_multi *multi, DEBUGASSERT(data->mstate == MSTATE_PENDING); /* Remove this node from the pending list */ - Curl_llist_remove(&multi->pending, &data->multi_queue, NULL); + Curl_node_remove(&data->multi_queue); /* put it into the process list */ - link_easy(multi, data); + Curl_llist_append(&multi->process, data, &data->multi_queue); multistate(data, MSTATE_CONNECT); @@ -3737,7 +3717,7 @@ static void move_pending_to_connect(struct Curl_multi *multi, Curl_expire(data, 0, EXPIRE_RUN_NOW); } -/* process_pending_handles() moves a handle from PENDING back into the main +/* process_pending_handles() moves a handle from PENDING back into the process list and change state to CONNECT. We do not move all transfers because that can be a significant amount. @@ -3753,9 +3733,9 @@ static void move_pending_to_connect(struct Curl_multi *multi, */ static void process_pending_handles(struct Curl_multi *multi) { - struct Curl_llist_element *e = multi->pending.head; + struct Curl_llist_node *e = Curl_llist_head(&multi->pending); if(e) { - struct Curl_easy *data = e->ptr; + struct Curl_easy *data = Curl_node_elem(e); move_pending_to_connect(multi, data); } } @@ -3783,9 +3763,9 @@ struct Curl_easy **curl_multi_get_handles(struct Curl_multi *multi) (multi->num_easy + 1)); if(a) { unsigned int i = 0; - struct Curl_llist_element *e; - for(e = multi->process.head; e; e = e->next) { - struct Curl_easy *data = e->ptr; + struct Curl_llist_node *e; + for(e = Curl_llist_head(&multi->process); e; e = Curl_node_next(e)) { + struct Curl_easy *data = Curl_node_elem(e); DEBUGASSERT(i < multi->num_easy); if(!data->state.internal) a[i++] = data; diff --git a/lib/multihandle.h b/lib/multihandle.h index 09bfe89a1a..0649e623aa 100644 --- a/lib/multihandle.h +++ b/lib/multihandle.h @@ -33,7 +33,7 @@ struct connectdata; struct Curl_message { - struct Curl_llist_element list; + struct Curl_llist_node list; /* the 'CURLMsg' is the part that is visible to the external user */ struct CURLMsg extmsg; }; @@ -92,7 +92,7 @@ struct Curl_multi { struct Curl_llist msglist; /* a list of messages from completed transfers */ - /* Each added easy handle is in ONE of these three lists */ + /* Each added easy handle is added to ONE of these three lists */ struct Curl_llist process; /* not in PENDING or MSGSENT */ struct Curl_llist pending; /* in PENDING */ struct Curl_llist msgsent; /* in MSGSENT */ diff --git a/lib/url.c b/lib/url.c index cd847899ee..d5d7e2fcca 100644 --- a/lib/url.c +++ b/lib/url.c @@ -539,6 +539,9 @@ CURLcode Curl_open(struct Curl_easy **curl) data->progress.flags |= PGRS_HIDE; data->state.current_speed = -1; /* init to negative == impossible */ +#ifndef CURL_DISABLE_HTTP + Curl_llist_init(&data->state.httphdrs, NULL); +#endif } if(result) { @@ -551,7 +554,6 @@ CURLcode Curl_open(struct Curl_easy **curl) } else *curl = data; - return result; } @@ -895,7 +897,7 @@ ConnectionExists(struct Curl_easy *data, bool foundPendingCandidate = FALSE; bool canmultiplex = FALSE; struct connectbundle *bundle; - struct Curl_llist_element *curr; + struct Curl_llist_node *curr; #ifdef USE_NTLM bool wantNTLMhttp = ((data->state.authhost.want & CURLAUTH_NTLM) && @@ -952,12 +954,12 @@ ConnectionExists(struct Curl_easy *data, } } - curr = bundle->conn_list.head; + curr = Curl_llist_head(&bundle->conn_list); while(curr) { - struct connectdata *check = curr->ptr; + struct connectdata *check = Curl_node_elem(curr); /* Get next node now. We might remove a dead `check` connection which * would invalidate `curr` as well. */ - curr = curr->next; + curr = Curl_node_next(curr); /* Note that if we use an HTTP proxy in normal mode (no tunneling), we * check connections to that proxy and not to the actual remote server. @@ -987,8 +989,8 @@ ConnectionExists(struct Curl_easy *data, } else { /* Could multiplex, but not when check belongs to another multi */ - struct Curl_llist_element *e = check->easyq.head; - struct Curl_easy *entry = e->ptr; + struct Curl_llist_node *e = Curl_llist_head(&check->easyq); + struct Curl_easy *entry = Curl_node_elem(e); if(entry->multi != data->multi) continue; } diff --git a/lib/urldata.h b/lib/urldata.h index d8bff3c9ba..2e71abdaf7 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -797,7 +797,7 @@ struct ldapconninfo; * unique for an entire connection. */ struct connectdata { - struct Curl_llist_element bundle_node; /* conncache */ + struct Curl_llist_node bundle_node; /* conncache */ curl_closesocket_callback fclosesocket; /* function closing the socket(s) */ void *closesocket_client; @@ -806,7 +806,7 @@ struct connectdata { handle is still used by one or more easy handles and can only used by any other easy handle without careful consideration (== only for multiplexing) and it cannot be used by another multi handle! */ -#define CONN_INUSE(c) ((c)->easyq.size) +#define CONN_INUSE(c) Curl_llist_count(&(c)->easyq) /**** Fields set when inited and not modified again */ curl_off_t connection_id; /* Contains a unique number to make it easier to @@ -1194,7 +1194,7 @@ typedef enum { * One instance for each timeout an easy handle can set. */ struct time_node { - struct Curl_llist_element list; + struct Curl_llist_node list; struct curltime time; expire_id eid; }; @@ -1910,8 +1910,8 @@ struct Curl_easy { curl_off_t id; struct connectdata *conn; - struct Curl_llist_element multi_queue; /* for multihandle list management */ - struct Curl_llist_element conn_queue; /* list per connectdata */ + struct Curl_llist_node multi_queue; /* for multihandle list management */ + struct Curl_llist_node conn_queue; /* list per connectdata */ CURLMstate mstate; /* the handle's state */ CURLcode result; /* previous result */ diff --git a/lib/vquic/curl_ngtcp2.c b/lib/vquic/curl_ngtcp2.c index e5a80b6c59..f672bfcaeb 100644 --- a/lib/vquic/curl_ngtcp2.c +++ b/lib/vquic/curl_ngtcp2.c @@ -274,10 +274,10 @@ static struct Curl_easy *get_stream_easy(struct Curl_cfilter *cf, return data; } else { - struct Curl_llist_element *e; + struct Curl_llist_node *e; DEBUGASSERT(data->multi); - for(e = data->multi->process.head; e; e = e->next) { - struct Curl_easy *sdata = e->ptr; + for(e = Curl_llist_head(&data->multi->process); e; e = Curl_node_next(e)) { + struct Curl_easy *sdata = Curl_node_elem(e); if(sdata->conn != data->conn) continue; stream = H3_STREAM_CTX(ctx, sdata); diff --git a/lib/vquic/curl_osslq.c b/lib/vquic/curl_osslq.c index c6dbcd6578..46565bee42 100644 --- a/lib/vquic/curl_osslq.c +++ b/lib/vquic/curl_osslq.c @@ -669,10 +669,10 @@ static struct cf_osslq_stream *cf_osslq_get_qstream(struct Curl_cfilter *cf, return &ctx->h3.s_qpack_dec; } else { - struct Curl_llist_element *e; + struct Curl_llist_node *e; DEBUGASSERT(data->multi); - for(e = data->multi->process.head; e; e = e->next) { - struct Curl_easy *sdata = e->ptr; + for(e = Curl_llist_head(&data->multi->process); e; e = Curl_node_next(e)) { + struct Curl_easy *sdata = Curl_node_elem(e); if(sdata->conn != data->conn) continue; stream = H3_STREAM_CTX(ctx, sdata); @@ -1423,12 +1423,12 @@ static CURLcode cf_progress_ingress(struct Curl_cfilter *cf, } if(ctx->h3.conn) { - struct Curl_llist_element *e; + struct Curl_llist_node *e; struct h3_stream_ctx *stream; /* PULL all open streams */ DEBUGASSERT(data->multi); - for(e = data->multi->process.head; e; e = e->next) { - struct Curl_easy *sdata = e->ptr; + for(e = Curl_llist_head(&data->multi->process); e; e = Curl_node_next(e)) { + struct Curl_easy *sdata = Curl_node_elem(e); if(sdata->conn == data->conn && CURL_WANT_RECV(sdata)) { stream = H3_STREAM_CTX(ctx, sdata); if(stream && !stream->closed && @@ -1454,9 +1454,9 @@ static CURLcode cf_osslq_check_and_unblock(struct Curl_cfilter *cf, struct h3_stream_ctx *stream; if(ctx->h3.conn) { - struct Curl_llist_element *e; - for(e = data->multi->process.head; e; e = e->next) { - struct Curl_easy *sdata = e->ptr; + struct Curl_llist_node *e; + for(e = Curl_llist_head(&data->multi->process); e; e = Curl_node_next(e)) { + struct Curl_easy *sdata = Curl_node_elem(e); if(sdata->conn == data->conn) { stream = H3_STREAM_CTX(ctx, sdata); if(stream && stream->s.ssl && stream->s.send_blocked && diff --git a/lib/vquic/curl_quiche.c b/lib/vquic/curl_quiche.c index 2247dd9064..fafbb03ee6 100644 --- a/lib/vquic/curl_quiche.c +++ b/lib/vquic/curl_quiche.c @@ -177,11 +177,11 @@ static void check_resumes(struct Curl_cfilter *cf, struct Curl_easy *data) { struct cf_quiche_ctx *ctx = cf->ctx; - struct Curl_llist_element *e; + struct Curl_llist_node *e; DEBUGASSERT(data->multi); - for(e = data->multi->process.head; e; e = e->next) { - struct Curl_easy *sdata = e->ptr; + for(e = Curl_llist_head(&data->multi->process); e; e = Curl_node_next(e)) { + struct Curl_easy *sdata = Curl_node_elem(e); if(sdata->conn == data->conn) { struct stream_ctx *stream = H3_STREAM_CTX(ctx, sdata); if(stream && stream->quic_flow_blocked) { @@ -277,10 +277,10 @@ static struct Curl_easy *get_stream_easy(struct Curl_cfilter *cf, return data; } else { - struct Curl_llist_element *e; + struct Curl_llist_node *e; DEBUGASSERT(data->multi); - for(e = data->multi->process.head; e; e = e->next) { - struct Curl_easy *sdata = e->ptr; + for(e = Curl_llist_head(&data->multi->process); e; e = Curl_node_next(e)) { + struct Curl_easy *sdata = Curl_node_elem(e); if(sdata->conn != data->conn) continue; stream = H3_STREAM_CTX(ctx, sdata); @@ -297,12 +297,12 @@ static struct Curl_easy *get_stream_easy(struct Curl_cfilter *cf, static void cf_quiche_expire_conn_closed(struct Curl_cfilter *cf, struct Curl_easy *data) { - struct Curl_llist_element *e; + struct Curl_llist_node *e; DEBUGASSERT(data->multi); CURL_TRC_CF(data, cf, "conn closed, expire all transfers"); - for(e = data->multi->process.head; e; e = e->next) { - struct Curl_easy *sdata = e->ptr; + for(e = Curl_llist_head(&data->multi->process); e; e = Curl_node_next(e)) { + struct Curl_easy *sdata = Curl_node_elem(e); if(sdata == data || sdata->conn != data->conn) continue; CURL_TRC_CF(sdata, cf, "conn closed, expire transfer"); diff --git a/tests/unit/unit1300.c b/tests/unit/unit1300.c index d94cfe1787..e408f5ecc2 100644 --- a/tests/unit/unit1300.c +++ b/tests/unit/unit1300.c @@ -52,14 +52,14 @@ UNITTEST_START int unusedData_case1 = 1; int unusedData_case2 = 2; int unusedData_case3 = 3; - struct Curl_llist_element case1_list; - struct Curl_llist_element case2_list; - struct Curl_llist_element case3_list; - struct Curl_llist_element case4_list; - struct Curl_llist_element *head; - struct Curl_llist_element *element_next; - struct Curl_llist_element *element_prev; - struct Curl_llist_element *to_remove; + struct Curl_llist_node case1_list; + struct Curl_llist_node case2_list; + struct Curl_llist_node case3_list; + struct Curl_llist_node case4_list; + struct Curl_llist_node *head; + struct Curl_llist_node *element_next; + struct Curl_llist_node *element_prev; + struct Curl_llist_node *to_remove; size_t llist_size = Curl_llist_count(&llist); /** @@ -73,11 +73,9 @@ UNITTEST_START * 4: list dtor will be NULL */ - fail_unless(llist.size == 0, "list initial size should be zero"); - fail_unless(llist.head == NULL, "list head should initiate to NULL"); - fail_unless(llist.tail == NULL, "list tail should initiate to NULL"); - fail_unless(llist.dtor == test_Curl_llist_dtor, - "list dtor should initiate to test_Curl_llist_dtor"); + fail_unless(Curl_llist_count(&llist) == 0, "list initial size should be zero"); + fail_unless(Curl_llist_head(&llist) == NULL, "list head should initiate to NULL"); + fail_unless(Curl_llist_tail(&llist) == NULL, "list tail should initiate to NULL"); /** * testing Curl_llist_insert_next @@ -89,15 +87,15 @@ UNITTEST_START * 3: list tail will be the same as list head */ - Curl_llist_insert_next(&llist, llist.head, &unusedData_case1, &case1_list); + Curl_llist_insert_next(&llist, Curl_llist_head(&llist), &unusedData_case1, &case1_list); fail_unless(Curl_llist_count(&llist) == 1, "List size should be 1 after adding a new element"); /* test that the list head data holds my unusedData */ - fail_unless(llist.head->ptr == &unusedData_case1, + fail_unless(Curl_node_elem(Curl_llist_head(&llist)) == &unusedData_case1, "head ptr should be first entry"); /* same goes for the list tail */ - fail_unless(llist.tail == llist.head, + fail_unless(Curl_llist_tail(&llist) == Curl_llist_head(&llist), "tail and head should be the same"); /** @@ -109,11 +107,12 @@ UNITTEST_START * 2: the list tail should be our newly created element */ - Curl_llist_insert_next(&llist, llist.head, + Curl_llist_insert_next(&llist, Curl_llist_head(&llist), &unusedData_case3, &case3_list); - fail_unless(llist.head->next->ptr == &unusedData_case3, + fail_unless(Curl_node_elem(Curl_node_next(Curl_llist_head(&llist))) == + &unusedData_case3, "the node next to head is not getting set correctly"); - fail_unless(llist.tail->ptr == &unusedData_case3, + fail_unless(Curl_node_elem(Curl_llist_tail(&llist)) == &unusedData_case3, "the list tail is not getting set correctly"); /** @@ -125,15 +124,16 @@ UNITTEST_START * 2: the list tail should different from newly created element */ - Curl_llist_insert_next(&llist, llist.head, + Curl_llist_insert_next(&llist, Curl_llist_head(&llist), &unusedData_case2, &case2_list); - fail_unless(llist.head->next->ptr == &unusedData_case2, + fail_unless(Curl_node_elem(Curl_node_next(Curl_llist_head(&llist))) == + &unusedData_case2, "the node next to head is not getting set correctly"); /* better safe than sorry, check that the tail isn't corrupted */ - fail_unless(llist.tail->ptr != &unusedData_case2, + fail_unless(Curl_node_elem(Curl_llist_tail(&llist)) != &unusedData_case2, "the list tail is not getting set correctly"); - /* unit tests for Curl_llist_remove */ + /* unit tests for Curl_node_remove */ /** * case 1: @@ -144,19 +144,19 @@ UNITTEST_START * 3: "new" head's previous will be NULL */ - head = llist.head; + head = Curl_llist_head(&llist); abort_unless(head, "llist.head is NULL"); - element_next = head->next; + element_next = Curl_node_next(head); llist_size = Curl_llist_count(&llist); - Curl_llist_remove(&llist, llist.head, NULL); + Curl_node_remove(Curl_llist_head(&llist)); fail_unless(Curl_llist_count(&llist) == (llist_size-1), - "llist size not decremented as expected"); - fail_unless(llist.head == element_next, - "llist new head not modified properly"); - abort_unless(llist.head, "llist.head is NULL"); - fail_unless(llist.head->prev == NULL, + "llist size not decremented as expected"); + fail_unless(Curl_llist_head(&llist) == element_next, + "llist new head not modified properly"); + abort_unless(Curl_llist_head(&llist), "llist.head is NULL"); + fail_unless(Curl_node_prev(Curl_llist_head(&llist)) == NULL, "new head previous not set to null"); /** @@ -169,20 +169,20 @@ UNITTEST_START * 2: element->previous->next will be element->next * 3: element->next->previous will be element->previous */ - Curl_llist_insert_next(&llist, llist.head, &unusedData_case3, + Curl_llist_insert_next(&llist, Curl_llist_head(&llist), &unusedData_case3, &case4_list); llist_size = Curl_llist_count(&llist); fail_unless(llist_size == 3, "should be 3 list members"); - to_remove = llist.head->next; + to_remove = Curl_node_next(Curl_llist_head(&llist)); abort_unless(to_remove, "to_remove is NULL"); - element_next = to_remove->next; - element_prev = to_remove->prev; - Curl_llist_remove(&llist, to_remove, NULL); - fail_unless(element_prev->next == element_next, + element_next = Curl_node_next(to_remove); + element_prev = Curl_node_prev(to_remove); + Curl_node_uremove(to_remove, NULL); + fail_unless(Curl_node_next(element_prev) == element_next, "element previous->next is not being adjusted"); abort_unless(element_next, "element_next is NULL"); - fail_unless(element_next->prev == element_prev, + fail_unless(Curl_node_prev(element_next) == element_prev, "element next->previous is not being adjusted"); /** @@ -195,10 +195,10 @@ UNITTEST_START * 4: list->tail will be tail->previous */ - to_remove = llist.tail; - element_prev = to_remove->prev; - Curl_llist_remove(&llist, to_remove, NULL); - fail_unless(llist.tail == element_prev, + to_remove = Curl_llist_tail(&llist); + element_prev = Curl_node_prev(to_remove); + Curl_node_remove(to_remove); + fail_unless(Curl_llist_tail(&llist) == element_prev, "llist tail is not being adjusted when removing tail"); /** @@ -210,11 +210,11 @@ UNITTEST_START * 3: list tail will be null */ - to_remove = llist.head; - Curl_llist_remove(&llist, to_remove, NULL); - fail_unless(llist.head == NULL, + to_remove = Curl_llist_head(&llist); + Curl_node_remove(to_remove); + fail_unless(Curl_llist_head(&llist) == NULL, "llist head is not NULL while the llist is empty"); - fail_unless(llist.tail == NULL, + fail_unless(Curl_llist_tail(&llist) == NULL, "llist tail is not NULL while the llist is empty"); /** @@ -229,10 +229,10 @@ UNITTEST_START fail_unless(Curl_llist_count(&llist) == 1, "List size should be 1 after appending a new element"); /* test that the list head data holds my unusedData */ - fail_unless(llist.head->ptr == &unusedData_case1, + fail_unless(Curl_node_elem(Curl_llist_head(&llist)) == &unusedData_case1, "head ptr should be first entry"); /* same goes for the list tail */ - fail_unless(llist.tail == llist.head, + fail_unless(Curl_llist_tail(&llist) == Curl_llist_head(&llist), "tail and head should be the same"); /** @@ -244,9 +244,10 @@ UNITTEST_START * 2: the list tail should be the newly created element */ Curl_llist_append(&llist, &unusedData_case2, &case2_list); - fail_unless(llist.head->next->ptr == &unusedData_case2, + fail_unless(Curl_node_elem(Curl_node_next(Curl_llist_head(&llist))) == + &unusedData_case2, "the node next to head is not getting set correctly"); - fail_unless(llist.tail->ptr == &unusedData_case2, + fail_unless(Curl_node_elem(Curl_llist_tail(&llist)) == &unusedData_case2, "the list tail is not getting set correctly"); /** @@ -258,13 +259,12 @@ UNITTEST_START * 2: the list tail should be the newly created element */ Curl_llist_append(&llist, &unusedData_case3, &case3_list); - fail_unless(llist.head->next->ptr == &unusedData_case2, + fail_unless(Curl_node_elem(Curl_node_next(Curl_llist_head(&llist))) == + &unusedData_case2, "the node next to head did not stay the same"); - fail_unless(llist.tail->ptr == &unusedData_case3, + fail_unless(Curl_node_elem(Curl_llist_tail(&llist)) == &unusedData_case3, "the list tail is not getting set correctly"); - - Curl_llist_destroy(&llist, NULL); Curl_llist_destroy(&llist_destination, NULL); } diff --git a/tests/unit/unit1654.c b/tests/unit/unit1654.c index f7ca3911b6..2f5d1bcc86 100644 --- a/tests/unit/unit1654.c +++ b/tests/unit/unit1654.c @@ -57,51 +57,51 @@ UNITTEST_START fail_if(!curl, "curl_easy_init"); goto fail; } - fail_unless(asi->list.size == 4, "wrong number of entries"); + fail_unless(Curl_llist_count(&asi->list) == 4, "wrong number of entries"); msnprintf(outname, sizeof(outname), "%s-out", arg); result = Curl_altsvc_parse(curl, asi, "h2=\"example.com:8080\"\r\n", ALPN_h1, "example.org", 8080); fail_if(result, "Curl_altsvc_parse() failed!"); - fail_unless(asi->list.size == 5, "wrong number of entries"); + fail_unless(Curl_llist_count(&asi->list) == 5, "wrong number of entries"); result = Curl_altsvc_parse(curl, asi, "h3=\":8080\"\r\n", ALPN_h1, "2.example.org", 8080); fail_if(result, "Curl_altsvc_parse(2) failed!"); - fail_unless(asi->list.size == 6, "wrong number of entries"); + fail_unless(Curl_llist_count(&asi->list) == 6, "wrong number of entries"); result = Curl_altsvc_parse(curl, asi, "h2=\"example.com:8080\", h3=\"yesyes.com\"\r\n", ALPN_h1, "3.example.org", 8080); fail_if(result, "Curl_altsvc_parse(3) failed!"); /* that one should make two entries */ - fail_unless(asi->list.size == 8, "wrong number of entries"); + fail_unless(Curl_llist_count(&asi->list) == 8, "wrong number of entries"); result = Curl_altsvc_parse(curl, asi, "h2=\"example.com:443\"; ma = 120;\r\n", ALPN_h2, "example.org", 80); fail_if(result, "Curl_altsvc_parse(4) failed!"); - fail_unless(asi->list.size == 9, "wrong number of entries"); + fail_unless(Curl_llist_count(&asi->list) == 9, "wrong number of entries"); /* quoted 'ma' value */ result = Curl_altsvc_parse(curl, asi, "h2=\"example.net:443\"; ma=\"180\";\r\n", ALPN_h2, "example.net", 80); fail_if(result, "Curl_altsvc_parse(4) failed!"); - fail_unless(asi->list.size == 10, "wrong number of entries"); + fail_unless(Curl_llist_count(&asi->list) == 10, "wrong number of entries"); result = Curl_altsvc_parse(curl, asi, "h2=\":443\", h3=\":443\"; ma = 120; persist = 1\r\n", ALPN_h1, "curl.se", 80); fail_if(result, "Curl_altsvc_parse(5) failed!"); - fail_unless(asi->list.size == 12, "wrong number of entries"); + fail_unless(Curl_llist_count(&asi->list) == 12, "wrong number of entries"); /* clear that one again and decrease the counter */ result = Curl_altsvc_parse(curl, asi, "clear;\r\n", ALPN_h1, "curl.se", 80); fail_if(result, "Curl_altsvc_parse(6) failed!"); - fail_unless(asi->list.size == 10, "wrong number of entries"); + fail_unless(Curl_llist_count(&asi->list) == 10, "wrong number of entries"); Curl_altsvc_save(curl, asi, outname); diff --git a/tests/unit/unit1660.c b/tests/unit/unit1660.c index 5a126fbc5a..e14944592c 100644 --- a/tests/unit/unit1660.c +++ b/tests/unit/unit1660.c @@ -118,6 +118,7 @@ static void showsts(struct stsentry *e, const char *chost) } UNITTEST_START +{ CURLcode result; struct stsentry *e; struct hsts *h = Curl_hsts_init(); @@ -159,7 +160,7 @@ UNITTEST_START showsts(e, chost); } - printf("Number of entries: %zu\n", h->list.size); + printf("Number of entries: %zu\n", Curl_llist_count(&h->list)); /* verify that it is exists for 7 seconds */ chost = "expire.example"; @@ -174,6 +175,6 @@ UNITTEST_START Curl_hsts_cleanup(&h); curl_easy_cleanup(easy); curl_global_cleanup(); - +} UNITTEST_STOP #endif