- 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
--- /dev/null
+<!--
+Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+
+SPDX-License-Identifier: curl
+-->
+
+# `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.
INSTALL.md \
INTERNALS.md \
IPFS.md \
+ LLIST.md \
KNOWN_BUGS \
MAIL-ETIQUETTE.md \
MANUAL.md \
*/
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);
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;
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;
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);
}
}
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;
}
time_t expires;
bool persist;
unsigned int prio;
- struct Curl_llist_element node;
+ struct Curl_llist_node node;
};
struct altsvcinfo {
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;
if(connc) {
Curl_hash_destroy(&connc->hash);
connc->multi = NULL;
- DEBUGASSERT(!Curl_llist_count(&connc->shutdowns.conn_list));
}
}
struct connectdata *conn, void *param))
{
struct Curl_hash_iterator iter;
- struct Curl_llist_element *curr;
struct Curl_hash_element *he;
if(!connc)
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);
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);
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;
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 */
conn_candidate = conn;
}
}
- curr = curr->next;
+ curr = Curl_node_next(curr);
}
if(conn_candidate) {
/* remove it to prevent another thread from nicking it */
{
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;
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) {
bundle_candidate = bundle;
}
}
- curr = curr->next;
+ curr = Curl_node_next(curr);
}
he = Curl_hash_next_element(&iter);
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)
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;
}
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);
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);
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);
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;
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 {
{
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;
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);
", 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;
}
}
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;
}
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)
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");
}
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 */
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;
struct fileinfo {
struct curl_fileinfo info;
- struct Curl_llist_element list;
+ struct Curl_llist_node list;
struct dynbuf buf;
};
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;
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);
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:
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 */
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;
}
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);
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;
}
*/
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;
}
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;
}
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;
/* 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;
}
}
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;
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;
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,
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;
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;
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)) {
/* 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) &&
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;
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);
}
/* 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))
/* 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);
*/
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);
#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.. */
{
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);
/* 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;
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;
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;
}
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;
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;
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;
#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 */
#ifdef DEBUGBUILD
else
infof(data, "Parsed STS header fine (%zu entries)",
- data->hsts->list.size);
+ Curl_llist_count(&data->hsts->list));
#endif
}
#endif
/* 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
}
/*
* @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;
}
/*
*/
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
#include "curl_setup.h"
#include <stddef.h>
-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 */
#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)
{
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);
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++;
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;
}
{
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 */
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 */
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
/* 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;
}
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;
}
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))
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);
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;
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;
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;
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)) {
/* 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++) {
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;
}
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;
}
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))
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 */
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);
}
}
}
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;
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);
!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));
{
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 */
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));
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));
}
}
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;
}
}
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;
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;
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");
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);
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.
*/
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);
}
}
(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;
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;
};
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 */
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) {
}
else
*curl = data;
-
return result;
}
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) &&
}
}
- 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.
}
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;
}
* 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;
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
* 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;
};
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 */
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);
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);
}
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 &&
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 &&
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) {
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);
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");
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);
/**
* 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
* 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");
/**
* 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");
/**
* 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:
* 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");
/**
* 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");
/**
* 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");
/**
* 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");
/**
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");
/**
* 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");
/**
* 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);
}
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);
}
UNITTEST_START
+{
CURLcode result;
struct stsentry *e;
struct hsts *h = Curl_hsts_init();
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";
Curl_hsts_cleanup(&h);
curl_easy_cleanup(easy);
curl_global_cleanup();
-
+}
UNITTEST_STOP
#endif