diff options
Diffstat (limited to 'libs/libcurl/src/pipeline.c')
-rw-r--r-- | libs/libcurl/src/pipeline.c | 278 |
1 files changed, 174 insertions, 104 deletions
diff --git a/libs/libcurl/src/pipeline.c b/libs/libcurl/src/pipeline.c index 418058afa0..4d41b04139 100644 --- a/libs/libcurl/src/pipeline.c +++ b/libs/libcurl/src/pipeline.c @@ -6,11 +6,11 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2013, Linus Nielsen Feltzing, <linus@haxx.se> - * Copyright (C) 2013, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2013 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -31,36 +31,32 @@ #include "multiif.h" #include "pipeline.h" #include "sendf.h" -#include "rawstr.h" -#include "bundles.h" +#include "strcase.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" struct site_blacklist_entry { - char *hostname; + struct curl_llist_element list; unsigned short port; + char hostname[1]; }; static void site_blacklist_llist_dtor(void *user, void *element) { struct site_blacklist_entry *entry = element; (void)user; - - Curl_safefree(entry->hostname); - Curl_safefree(entry); + free(entry); } static void server_blacklist_llist_dtor(void *user, void *element) { - char *server_name = element; (void)user; - - Curl_safefree(server_name); + free(element); } -bool Curl_pipeline_penalized(struct SessionHandle *data, +bool Curl_pipeline_penalized(struct Curl_easy *data, struct connectdata *conn) { if(data) { @@ -72,8 +68,8 @@ bool Curl_pipeline_penalized(struct SessionHandle *data, curl_off_t recv_size = -2; /* Make it easy to spot in the log */ /* Find the head of the recv pipe, if any */ - if(conn->recv_pipe && conn->recv_pipe->head) { - struct SessionHandle *recv_handle = conn->recv_pipe->head->ptr; + if(conn->recv_pipe.head) { + struct Curl_easy *recv_handle = conn->recv_pipe.head->ptr; recv_size = recv_handle->req.size; @@ -85,8 +81,8 @@ bool Curl_pipeline_penalized(struct SessionHandle *data, (curl_off_t)conn->chunk.datasize > chunk_penalty_size) penalized = TRUE; - infof(data, "Conn: %ld (%p) Receive pipe weight: (%" FORMAT_OFF_T - "/%zu), penalized: %s\n", + infof(data, "Conn: %ld (%p) Receive pipe weight: (%" + CURL_FORMAT_CURL_OFF_T "/%zu), penalized: %s\n", conn->connection_id, (void *)conn, recv_size, conn->chunk.datasize, penalized?"TRUE":"FALSE"); return penalized; @@ -94,33 +90,37 @@ bool Curl_pipeline_penalized(struct SessionHandle *data, return FALSE; } -CURLcode Curl_add_handle_to_pipeline(struct SessionHandle *handle, +static CURLcode addHandleToPipeline(struct Curl_easy *data, + struct curl_llist *pipeline) +{ + Curl_llist_insert_next(pipeline, pipeline->tail, data, + &data->pipeline_queue); + return CURLE_OK; +} + + +CURLcode Curl_add_handle_to_pipeline(struct Curl_easy *handle, struct connectdata *conn) { - struct curl_llist_element *sendhead = conn->send_pipe->head; + struct curl_llist_element *sendhead = conn->send_pipe.head; struct curl_llist *pipeline; - CURLcode rc; + CURLcode result; - pipeline = conn->send_pipe; + pipeline = &conn->send_pipe; - infof(conn->data, "Adding handle: conn: %p\n", (void *)conn); - infof(conn->data, "Adding handle: send: %d\n", conn->send_pipe->size); - infof(conn->data, "Adding handle: recv: %d\n", conn->recv_pipe->size); - rc = Curl_addHandleToPipeline(handle, pipeline); + result = addHandleToPipeline(handle, pipeline); - if(pipeline == conn->send_pipe && sendhead != conn->send_pipe->head) { + if(pipeline == &conn->send_pipe && sendhead != conn->send_pipe.head) { /* this is a new one as head, expire it */ - conn->writechannel_inuse = FALSE; /* not in use yet */ -#ifdef DEBUGBUILD - infof(conn->data, "%p is at send pipe head!\n", - (void *)conn->send_pipe->head->ptr); -#endif - Curl_expire(conn->send_pipe->head->ptr, 1); + Curl_pipeline_leave_write(conn); /* not in use yet */ + Curl_expire(conn->send_pipe.head->ptr, 0, EXPIRE_RUN_NOW); } +#if 0 /* enable for pipeline debugging */ print_pipeline(conn); +#endif - return rc; + return result; } /* Move this transfer from the sending list to the receiving list. @@ -129,26 +129,26 @@ CURLcode Curl_add_handle_to_pipeline(struct SessionHandle *handle, checked to update what sockets it acts on. */ -void Curl_move_handle_from_send_to_recv_pipe(struct SessionHandle *handle, +void Curl_move_handle_from_send_to_recv_pipe(struct Curl_easy *handle, struct connectdata *conn) { struct curl_llist_element *curr; - curr = conn->send_pipe->head; + curr = conn->send_pipe.head; while(curr) { if(curr->ptr == handle) { - Curl_llist_move(conn->send_pipe, curr, - conn->recv_pipe, conn->recv_pipe->tail); + Curl_llist_move(&conn->send_pipe, curr, + &conn->recv_pipe, conn->recv_pipe.tail); - if(conn->send_pipe->head) { + if(conn->send_pipe.head) { /* Since there's a new easy handle at the start of the send pipeline, set its timeout value to 1ms to make it trigger instantly */ - conn->writechannel_inuse = FALSE; /* not used now */ + Curl_pipeline_leave_write(conn); /* not used now */ #ifdef DEBUGBUILD infof(conn->data, "%p is at send pipe head B!\n", - (void *)conn->send_pipe->head->ptr); + (void *)conn->send_pipe.head->ptr); #endif - Curl_expire(conn->send_pipe->head->ptr, 1); + Curl_expire(conn->send_pipe.head->ptr, 0, EXPIRE_RUN_NOW); } /* The receiver's list is not really interesting here since either this @@ -161,7 +161,7 @@ void Curl_move_handle_from_send_to_recv_pipe(struct SessionHandle *handle, } } -bool Curl_pipeline_site_blacklisted(struct SessionHandle *handle, +bool Curl_pipeline_site_blacklisted(struct Curl_easy *handle, struct connectdata *conn) { if(handle->multi) { @@ -176,7 +176,7 @@ bool Curl_pipeline_site_blacklisted(struct SessionHandle *handle, struct site_blacklist_entry *site; site = curr->ptr; - if(Curl_raw_equal(site->hostname, conn->host.name) && + if(strcasecompare(site->hostname, conn->host.name) && site->port == conn->remote_port) { infof(handle, "Site %s:%d is pipeline blacklisted\n", conn->host.name, conn->remote_port); @@ -190,29 +190,28 @@ bool Curl_pipeline_site_blacklisted(struct SessionHandle *handle, } CURLMcode Curl_pipeline_set_site_blacklist(char **sites, - struct curl_llist **list_ptr) + struct curl_llist *list) { - struct curl_llist *old_list = *list_ptr; - struct curl_llist *new_list = NULL; + /* Free the old list */ + if(list->size) + Curl_llist_destroy(list, NULL); if(sites) { - new_list = Curl_llist_alloc((curl_llist_dtor) site_blacklist_llist_dtor); - if(!new_list) - return CURLM_OUT_OF_MEMORY; + Curl_llist_init(list, (curl_llist_dtor) site_blacklist_llist_dtor); /* Parse the URLs and populate the list */ while(*sites) { - char *hostname; char *port; struct site_blacklist_entry *entry; - entry = malloc(sizeof(struct site_blacklist_entry)); - - hostname = strdup(*sites); - if(!hostname) + entry = malloc(sizeof(struct site_blacklist_entry) + strlen(*sites)); + if(!entry) { + Curl_llist_destroy(list, NULL); return CURLM_OUT_OF_MEMORY; + } + strcpy(entry->hostname, *sites); - port = strchr(hostname, ':'); + port = strchr(entry->hostname, ':'); if(port) { *port = '\0'; port++; @@ -223,98 +222,167 @@ CURLMcode Curl_pipeline_set_site_blacklist(char **sites, entry->port = 80; } - entry->hostname = hostname; - - if(!Curl_llist_insert_next(new_list, new_list->tail, entry)) - return CURLM_OUT_OF_MEMORY; - + Curl_llist_insert_next(list, list->tail, entry, &entry->list); sites++; } } - /* Free the old list */ - if(old_list) { - Curl_llist_destroy(old_list, NULL); - } - - /* This might be NULL if sites == NULL, i.e the blacklist is cleared */ - *list_ptr = new_list; - return CURLM_OK; } -bool Curl_pipeline_server_blacklisted(struct SessionHandle *handle, +struct blacklist_node { + struct curl_llist_element list; + char server_name[1]; +}; + +bool Curl_pipeline_server_blacklisted(struct Curl_easy *handle, char *server_name) { - if(handle->multi) { - struct curl_llist *blacklist = + if(handle->multi && server_name) { + struct curl_llist *list = Curl_multi_pipelining_server_bl(handle->multi); - if(blacklist) { - struct curl_llist_element *curr; - - curr = blacklist->head; - while(curr) { - char *bl_server_name; - - bl_server_name = curr->ptr; - if(Curl_raw_nequal(bl_server_name, server_name, - strlen(bl_server_name))) { - infof(handle, "Server %s is blacklisted\n", server_name); - return TRUE; - } - curr = curr->next; + struct curl_llist_element *e = list->head; + while(e) { + struct blacklist_node *bl = (struct blacklist_node *)e; + if(strncasecompare(bl->server_name, server_name, + strlen(bl->server_name))) { + infof(handle, "Server %s is blacklisted\n", server_name); + return TRUE; } + e = e->next; } - infof(handle, "Server %s is not blacklisted\n", server_name); + DEBUGF(infof(handle, "Server %s is not blacklisted\n", server_name)); } return FALSE; } CURLMcode Curl_pipeline_set_server_blacklist(char **servers, - struct curl_llist **list_ptr) + struct curl_llist *list) { - struct curl_llist *old_list = *list_ptr; - struct curl_llist *new_list = NULL; + /* Free the old list */ + if(list->size) + Curl_llist_destroy(list, NULL); if(servers) { - new_list = Curl_llist_alloc((curl_llist_dtor) server_blacklist_llist_dtor); - if(!new_list) - return CURLM_OUT_OF_MEMORY; + Curl_llist_init(list, (curl_llist_dtor) server_blacklist_llist_dtor); /* Parse the URLs and populate the list */ while(*servers) { - char *server_name; - - server_name = strdup(*servers); - if(!server_name) - return CURLM_OUT_OF_MEMORY; + struct blacklist_node *n; + size_t len = strlen(*servers); - if(!Curl_llist_insert_next(new_list, new_list->tail, server_name)) + n = malloc(sizeof(struct blacklist_node) + len); + if(!n) { + Curl_llist_destroy(list, NULL); return CURLM_OUT_OF_MEMORY; + } + strcpy(n->server_name, *servers); + Curl_llist_insert_next(list, list->tail, n, &n->list); servers++; } } - /* Free the old list */ - if(old_list) { - Curl_llist_destroy(old_list, NULL); + + return CURLM_OK; +} + +static bool pipe_head(struct Curl_easy *data, + struct curl_llist *pipeline) +{ + if(pipeline) { + struct curl_llist_element *curr = pipeline->head; + if(curr) + return (curr->ptr == data) ? TRUE : FALSE; } + return FALSE; +} + +/* returns TRUE if the given handle is head of the recv pipe */ +bool Curl_recvpipe_head(struct Curl_easy *data, + struct connectdata *conn) +{ + return pipe_head(data, &conn->recv_pipe); +} - /* This might be NULL if sites == NULL, i.e the blacklist is cleared */ - *list_ptr = new_list; +/* returns TRUE if the given handle is head of the send pipe */ +bool Curl_sendpipe_head(struct Curl_easy *data, + struct connectdata *conn) +{ + return pipe_head(data, &conn->send_pipe); +} - return CURLM_OK; + +/* + * Check if the write channel is available and this handle as at the head, + * then grab the channel and return TRUE. + * + * If not available, return FALSE. + */ + +bool Curl_pipeline_checkget_write(struct Curl_easy *data, + struct connectdata *conn) +{ + if(conn->bits.multiplex) + /* when multiplexing, we can use it at once */ + return TRUE; + + if(!conn->writechannel_inuse && Curl_sendpipe_head(data, conn)) { + /* Grab the channel */ + conn->writechannel_inuse = TRUE; + return TRUE; + } + return FALSE; +} + + +/* + * Check if the read channel is available and this handle as at the head, then + * grab the channel and return TRUE. + * + * If not available, return FALSE. + */ + +bool Curl_pipeline_checkget_read(struct Curl_easy *data, + struct connectdata *conn) +{ + if(conn->bits.multiplex) + /* when multiplexing, we can use it at once */ + return TRUE; + + if(!conn->readchannel_inuse && Curl_recvpipe_head(data, conn)) { + /* Grab the channel */ + conn->readchannel_inuse = TRUE; + return TRUE; + } + return FALSE; } +/* + * The current user of the pipeline write channel gives it up. + */ +void Curl_pipeline_leave_write(struct connectdata *conn) +{ + conn->writechannel_inuse = FALSE; +} +/* + * The current user of the pipeline read channel gives it up. + */ +void Curl_pipeline_leave_read(struct connectdata *conn) +{ + conn->readchannel_inuse = FALSE; +} + + +#if 0 void print_pipeline(struct connectdata *conn) { struct curl_llist_element *curr; struct connectbundle *cb_ptr; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; cb_ptr = conn->bundle; @@ -331,3 +399,5 @@ void print_pipeline(struct connectdata *conn) } } } + +#endif |