pipeline.c
Go to the documentation of this file.
00001 /***************************************************************************
00002  *                                  _   _ ____  _
00003  *  Project                     ___| | | |  _ \| |
00004  *                             / __| | | | |_) | |
00005  *                            | (__| |_| |  _ <| |___
00006  *                             \___|\___/|_| \_\_____|
00007  *
00008  * Copyright (C) 2013, Linus Nielsen Feltzing, <linus@haxx.se>
00009  * Copyright (C) 2013-2016, Daniel Stenberg, <daniel@haxx.se>, et al.
00010  *
00011  * This software is licensed as described in the file COPYING, which
00012  * you should have received as part of this distribution. The terms
00013  * are also available at https://curl.haxx.se/docs/copyright.html.
00014  *
00015  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
00016  * copies of the Software, and permit persons to whom the Software is
00017  * furnished to do so, under the terms of the COPYING file.
00018  *
00019  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
00020  * KIND, either express or implied.
00021  *
00022  ***************************************************************************/
00023 
00024 #include "curl_setup.h"
00025 
00026 #include <curl/curl.h>
00027 
00028 #include "urldata.h"
00029 #include "url.h"
00030 #include "progress.h"
00031 #include "multiif.h"
00032 #include "pipeline.h"
00033 #include "sendf.h"
00034 #include "strcase.h"
00035 
00036 #include "curl_memory.h"
00037 /* The last #include file should be: */
00038 #include "memdebug.h"
00039 
00040 struct site_blacklist_entry {
00041   char *hostname;
00042   unsigned short port;
00043 };
00044 
00045 static void site_blacklist_llist_dtor(void *user, void *element)
00046 {
00047   struct site_blacklist_entry *entry = element;
00048   (void)user;
00049 
00050   Curl_safefree(entry->hostname);
00051   free(entry);
00052 }
00053 
00054 static void server_blacklist_llist_dtor(void *user, void *element)
00055 {
00056   (void)user;
00057   free(element);
00058 }
00059 
00060 bool Curl_pipeline_penalized(struct Curl_easy *data,
00061                              struct connectdata *conn)
00062 {
00063   if(data) {
00064     bool penalized = FALSE;
00065     curl_off_t penalty_size =
00066       Curl_multi_content_length_penalty_size(data->multi);
00067     curl_off_t chunk_penalty_size =
00068       Curl_multi_chunk_length_penalty_size(data->multi);
00069     curl_off_t recv_size = -2; /* Make it easy to spot in the log */
00070 
00071     /* Find the head of the recv pipe, if any */
00072     if(conn->recv_pipe && conn->recv_pipe->head) {
00073       struct Curl_easy *recv_handle = conn->recv_pipe->head->ptr;
00074 
00075       recv_size = recv_handle->req.size;
00076 
00077       if(penalty_size > 0 && recv_size > penalty_size)
00078         penalized = TRUE;
00079     }
00080 
00081     if(chunk_penalty_size > 0 &&
00082        (curl_off_t)conn->chunk.datasize > chunk_penalty_size)
00083       penalized = TRUE;
00084 
00085     infof(data, "Conn: %ld (%p) Receive pipe weight: (%"
00086           CURL_FORMAT_CURL_OFF_T "/%zu), penalized: %s\n",
00087           conn->connection_id, (void *)conn, recv_size,
00088           conn->chunk.datasize, penalized?"TRUE":"FALSE");
00089     return penalized;
00090   }
00091   return FALSE;
00092 }
00093 
00094 static CURLcode addHandleToPipeline(struct Curl_easy *data,
00095                                     struct curl_llist *pipeline)
00096 {
00097   if(!Curl_llist_insert_next(pipeline, pipeline->tail, data))
00098     return CURLE_OUT_OF_MEMORY;
00099   return CURLE_OK;
00100 }
00101 
00102 
00103 CURLcode Curl_add_handle_to_pipeline(struct Curl_easy *handle,
00104                                      struct connectdata *conn)
00105 {
00106   struct curl_llist_element *sendhead = conn->send_pipe->head;
00107   struct curl_llist *pipeline;
00108   CURLcode result;
00109 
00110   pipeline = conn->send_pipe;
00111 
00112   result = addHandleToPipeline(handle, pipeline);
00113 
00114   if(pipeline == conn->send_pipe && sendhead != conn->send_pipe->head) {
00115     /* this is a new one as head, expire it */
00116     Curl_pipeline_leave_write(conn); /* not in use yet */
00117     Curl_expire(conn->send_pipe->head->ptr, 0);
00118   }
00119 
00120 #if 0 /* enable for pipeline debugging */
00121   print_pipeline(conn);
00122 #endif
00123 
00124   return result;
00125 }
00126 
00127 /* Move this transfer from the sending list to the receiving list.
00128 
00129    Pay special attention to the new sending list "leader" as it needs to get
00130    checked to update what sockets it acts on.
00131 
00132 */
00133 void Curl_move_handle_from_send_to_recv_pipe(struct Curl_easy *handle,
00134                                              struct connectdata *conn)
00135 {
00136   struct curl_llist_element *curr;
00137 
00138   curr = conn->send_pipe->head;
00139   while(curr) {
00140     if(curr->ptr == handle) {
00141       Curl_llist_move(conn->send_pipe, curr,
00142                       conn->recv_pipe, conn->recv_pipe->tail);
00143 
00144       if(conn->send_pipe->head) {
00145         /* Since there's a new easy handle at the start of the send pipeline,
00146            set its timeout value to 1ms to make it trigger instantly */
00147         Curl_pipeline_leave_write(conn); /* not used now */
00148 #ifdef DEBUGBUILD
00149         infof(conn->data, "%p is at send pipe head B!\n",
00150               (void *)conn->send_pipe->head->ptr);
00151 #endif
00152         Curl_expire(conn->send_pipe->head->ptr, 0);
00153       }
00154 
00155       /* The receiver's list is not really interesting here since either this
00156          handle is now first in the list and we'll deal with it soon, or
00157          another handle is already first and thus is already taken care of */
00158 
00159       break; /* we're done! */
00160     }
00161     curr = curr->next;
00162   }
00163 }
00164 
00165 bool Curl_pipeline_site_blacklisted(struct Curl_easy *handle,
00166                                     struct connectdata *conn)
00167 {
00168   if(handle->multi) {
00169     struct curl_llist *blacklist =
00170       Curl_multi_pipelining_site_bl(handle->multi);
00171 
00172     if(blacklist) {
00173       struct curl_llist_element *curr;
00174 
00175       curr = blacklist->head;
00176       while(curr) {
00177         struct site_blacklist_entry *site;
00178 
00179         site = curr->ptr;
00180         if(strcasecompare(site->hostname, conn->host.name) &&
00181            site->port == conn->remote_port) {
00182           infof(handle, "Site %s:%d is pipeline blacklisted\n",
00183                 conn->host.name, conn->remote_port);
00184           return TRUE;
00185         }
00186         curr = curr->next;
00187       }
00188     }
00189   }
00190   return FALSE;
00191 }
00192 
00193 CURLMcode Curl_pipeline_set_site_blacklist(char **sites,
00194                                            struct curl_llist **list_ptr)
00195 {
00196   struct curl_llist *old_list = *list_ptr;
00197   struct curl_llist *new_list = NULL;
00198 
00199   if(sites) {
00200     new_list = Curl_llist_alloc((curl_llist_dtor) site_blacklist_llist_dtor);
00201     if(!new_list)
00202       return CURLM_OUT_OF_MEMORY;
00203 
00204     /* Parse the URLs and populate the list */
00205     while(*sites) {
00206       char *hostname;
00207       char *port;
00208       struct site_blacklist_entry *entry;
00209 
00210       hostname = strdup(*sites);
00211       if(!hostname) {
00212         Curl_llist_destroy(new_list, NULL);
00213         return CURLM_OUT_OF_MEMORY;
00214       }
00215 
00216       entry = malloc(sizeof(struct site_blacklist_entry));
00217       if(!entry) {
00218         free(hostname);
00219         Curl_llist_destroy(new_list, NULL);
00220         return CURLM_OUT_OF_MEMORY;
00221       }
00222 
00223       port = strchr(hostname, ':');
00224       if(port) {
00225         *port = '\0';
00226         port++;
00227         entry->port = (unsigned short)strtol(port, NULL, 10);
00228       }
00229       else {
00230         /* Default port number for HTTP */
00231         entry->port = 80;
00232       }
00233 
00234       entry->hostname = hostname;
00235 
00236       if(!Curl_llist_insert_next(new_list, new_list->tail, entry)) {
00237         site_blacklist_llist_dtor(NULL, entry);
00238         Curl_llist_destroy(new_list, NULL);
00239         return CURLM_OUT_OF_MEMORY;
00240       }
00241 
00242       sites++;
00243     }
00244   }
00245 
00246   /* Free the old list */
00247   if(old_list) {
00248     Curl_llist_destroy(old_list, NULL);
00249   }
00250 
00251   /* This might be NULL if sites == NULL, i.e the blacklist is cleared */
00252   *list_ptr = new_list;
00253 
00254   return CURLM_OK;
00255 }
00256 
00257 bool Curl_pipeline_server_blacklisted(struct Curl_easy *handle,
00258                                       char *server_name)
00259 {
00260   if(handle->multi && server_name) {
00261     struct curl_llist *blacklist =
00262       Curl_multi_pipelining_server_bl(handle->multi);
00263 
00264     if(blacklist) {
00265       struct curl_llist_element *curr;
00266 
00267       curr = blacklist->head;
00268       while(curr) {
00269         char *bl_server_name;
00270 
00271         bl_server_name = curr->ptr;
00272         if(strncasecompare(bl_server_name, server_name,
00273                            strlen(bl_server_name))) {
00274           infof(handle, "Server %s is blacklisted\n", server_name);
00275           return TRUE;
00276         }
00277         curr = curr->next;
00278       }
00279     }
00280 
00281     DEBUGF(infof(handle, "Server %s is not blacklisted\n", server_name));
00282   }
00283   return FALSE;
00284 }
00285 
00286 CURLMcode Curl_pipeline_set_server_blacklist(char **servers,
00287                                              struct curl_llist **list_ptr)
00288 {
00289   struct curl_llist *old_list = *list_ptr;
00290   struct curl_llist *new_list = NULL;
00291 
00292   if(servers) {
00293     new_list = Curl_llist_alloc((curl_llist_dtor) server_blacklist_llist_dtor);
00294     if(!new_list)
00295       return CURLM_OUT_OF_MEMORY;
00296 
00297     /* Parse the URLs and populate the list */
00298     while(*servers) {
00299       char *server_name;
00300 
00301       server_name = strdup(*servers);
00302       if(!server_name) {
00303         Curl_llist_destroy(new_list, NULL);
00304         return CURLM_OUT_OF_MEMORY;
00305       }
00306 
00307       if(!Curl_llist_insert_next(new_list, new_list->tail, server_name)) {
00308         Curl_llist_destroy(new_list, NULL);
00309         Curl_safefree(server_name);
00310         return CURLM_OUT_OF_MEMORY;
00311       }
00312 
00313       servers++;
00314     }
00315   }
00316 
00317   /* Free the old list */
00318   if(old_list) {
00319     Curl_llist_destroy(old_list, NULL);
00320   }
00321 
00322   /* This might be NULL if sites == NULL, i.e the blacklist is cleared */
00323   *list_ptr = new_list;
00324 
00325   return CURLM_OK;
00326 }
00327 
00328 static bool pipe_head(struct Curl_easy *data,
00329                       struct curl_llist *pipeline)
00330 {
00331   if(pipeline) {
00332     struct curl_llist_element *curr = pipeline->head;
00333     if(curr)
00334       return (curr->ptr == data) ? TRUE : FALSE;
00335   }
00336   return FALSE;
00337 }
00338 
00339 /* returns TRUE if the given handle is head of the recv pipe */
00340 bool Curl_recvpipe_head(struct Curl_easy *data,
00341                         struct connectdata *conn)
00342 {
00343   return pipe_head(data, conn->recv_pipe);
00344 }
00345 
00346 /* returns TRUE if the given handle is head of the send pipe */
00347 bool Curl_sendpipe_head(struct Curl_easy *data,
00348                         struct connectdata *conn)
00349 {
00350   return pipe_head(data, conn->send_pipe);
00351 }
00352 
00353 
00354 /*
00355  * Check if the write channel is available and this handle as at the head,
00356  * then grab the channel and return TRUE.
00357  *
00358  * If not available, return FALSE.
00359  */
00360 
00361 bool Curl_pipeline_checkget_write(struct Curl_easy *data,
00362                                   struct connectdata *conn)
00363 {
00364   if(conn->bits.multiplex)
00365     /* when multiplexing, we can use it at once */
00366     return TRUE;
00367 
00368   if(!conn->writechannel_inuse && Curl_sendpipe_head(data, conn)) {
00369     /* Grab the channel */
00370     conn->writechannel_inuse = TRUE;
00371     return TRUE;
00372   }
00373   return FALSE;
00374 }
00375 
00376 
00377 /*
00378  * Check if the read channel is available and this handle as at the head, then
00379  * grab the channel and return TRUE.
00380  *
00381  * If not available, return FALSE.
00382  */
00383 
00384 bool Curl_pipeline_checkget_read(struct Curl_easy *data,
00385                                  struct connectdata *conn)
00386 {
00387   if(conn->bits.multiplex)
00388     /* when multiplexing, we can use it at once */
00389     return TRUE;
00390 
00391   if(!conn->readchannel_inuse && Curl_recvpipe_head(data, conn)) {
00392     /* Grab the channel */
00393     conn->readchannel_inuse = TRUE;
00394     return TRUE;
00395   }
00396   return FALSE;
00397 }
00398 
00399 /*
00400  * The current user of the pipeline write channel gives it up.
00401  */
00402 void Curl_pipeline_leave_write(struct connectdata *conn)
00403 {
00404   conn->writechannel_inuse = FALSE;
00405 }
00406 
00407 /*
00408  * The current user of the pipeline read channel gives it up.
00409  */
00410 void Curl_pipeline_leave_read(struct connectdata *conn)
00411 {
00412   conn->readchannel_inuse = FALSE;
00413 }
00414 
00415 
00416 #if 0
00417 void print_pipeline(struct connectdata *conn)
00418 {
00419   struct curl_llist_element *curr;
00420   struct connectbundle *cb_ptr;
00421   struct Curl_easy *data = conn->data;
00422 
00423   cb_ptr = conn->bundle;
00424 
00425   if(cb_ptr) {
00426     curr = cb_ptr->conn_list->head;
00427     while(curr) {
00428       conn = curr->ptr;
00429       infof(data, "- Conn %ld (%p) send_pipe: %zu, recv_pipe: %zu\n",
00430             conn->connection_id,
00431             (void *)conn,
00432             conn->send_pipe->size,
00433             conn->recv_pipe->size);
00434       curr = curr->next;
00435     }
00436   }
00437 }
00438 
00439 #endif


rc_visard_driver
Author(s): Heiko Hirschmueller , Christian Emmerich , Felix Ruess
autogenerated on Thu Jun 6 2019 20:43:06