1e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET/*************************************************************************** 2e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET * _ _ ____ _ 3e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET * Project ___| | | | _ \| | 4e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET * / __| | | | |_) | | 5e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET * | (__| |_| | _ <| |___ 6e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET * \___|\___/|_| \_\_____| 7e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET * 8e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET * Copyright (C) 2013, Linus Nielsen Feltzing, <linus@haxx.se> 9e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET * Copyright (C) 2013-2015, Daniel Stenberg, <daniel@haxx.se>, et al. 10e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET * 11e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET * This software is licensed as described in the file COPYING, which 12e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET * you should have received as part of this distribution. The terms 13d15eaac64ca1a7244824d660ea84e8815a23d058Alex Deymo * are also available at https://curl.haxx.se/docs/copyright.html. 14e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET * 15e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET * You may opt to use, copy, modify, merge, publish, distribute and/or sell 16e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET * copies of the Software, and permit persons to whom the Software is 17e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET * furnished to do so, under the terms of the COPYING file. 18e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET * 19e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 20e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET * KIND, either express or implied. 21e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET * 22e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET ***************************************************************************/ 23e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 24e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET#include "curl_setup.h" 25e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 26e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET#include <curl/curl.h> 27e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 28e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET#include "urldata.h" 29e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET#include "url.h" 30e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET#include "progress.h" 31e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET#include "multiif.h" 32e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET#include "pipeline.h" 33e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET#include "sendf.h" 34e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET#include "rawstr.h" 35e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 36e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET#include "curl_memory.h" 37e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET/* The last #include file should be: */ 38e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET#include "memdebug.h" 39e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 40e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNETstruct site_blacklist_entry { 41e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET char *hostname; 42e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET unsigned short port; 43e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET}; 44e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 45e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNETstatic void site_blacklist_llist_dtor(void *user, void *element) 46e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET{ 47e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET struct site_blacklist_entry *entry = element; 48e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET (void)user; 49e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 50e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET Curl_safefree(entry->hostname); 51e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET free(entry); 52e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET} 53e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 54e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNETstatic void server_blacklist_llist_dtor(void *user, void *element) 55e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET{ 56e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET (void)user; 57e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET free(element); 58e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET} 59e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 60e3149cc1cf501b46caba8d47652ac90b95c78eacAlex Deymobool Curl_pipeline_penalized(struct Curl_easy *data, 61e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET struct connectdata *conn) 62e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET{ 63e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET if(data) { 64e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET bool penalized = FALSE; 65e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET curl_off_t penalty_size = 66e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET Curl_multi_content_length_penalty_size(data->multi); 67e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET curl_off_t chunk_penalty_size = 68e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET Curl_multi_chunk_length_penalty_size(data->multi); 69e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET curl_off_t recv_size = -2; /* Make it easy to spot in the log */ 70e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 71e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET /* Find the head of the recv pipe, if any */ 72e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET if(conn->recv_pipe && conn->recv_pipe->head) { 73e3149cc1cf501b46caba8d47652ac90b95c78eacAlex Deymo struct Curl_easy *recv_handle = conn->recv_pipe->head->ptr; 74e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 75e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET recv_size = recv_handle->req.size; 76e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 77e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET if(penalty_size > 0 && recv_size > penalty_size) 78e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET penalized = TRUE; 79e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET } 80e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 81e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET if(chunk_penalty_size > 0 && 82e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET (curl_off_t)conn->chunk.datasize > chunk_penalty_size) 83e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET penalized = TRUE; 84e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 85e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET infof(data, "Conn: %ld (%p) Receive pipe weight: (%" 86e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET CURL_FORMAT_CURL_OFF_T "/%zu), penalized: %s\n", 87e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET conn->connection_id, (void *)conn, recv_size, 88e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET conn->chunk.datasize, penalized?"TRUE":"FALSE"); 89e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET return penalized; 90e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET } 91e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET return FALSE; 92e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET} 93e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 94e3149cc1cf501b46caba8d47652ac90b95c78eacAlex Deymostatic CURLcode addHandleToPipeline(struct Curl_easy *data, 95e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET struct curl_llist *pipeline) 96e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET{ 97e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET if(!Curl_llist_insert_next(pipeline, pipeline->tail, data)) 98e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET return CURLE_OUT_OF_MEMORY; 99e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET return CURLE_OK; 100e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET} 101e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 102e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 103e3149cc1cf501b46caba8d47652ac90b95c78eacAlex DeymoCURLcode Curl_add_handle_to_pipeline(struct Curl_easy *handle, 104e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET struct connectdata *conn) 105e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET{ 106e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET struct curl_llist_element *sendhead = conn->send_pipe->head; 107e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET struct curl_llist *pipeline; 108e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET CURLcode result; 109e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 110e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET pipeline = conn->send_pipe; 111e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 112e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET result = addHandleToPipeline(handle, pipeline); 113e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 114e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET if(pipeline == conn->send_pipe && sendhead != conn->send_pipe->head) { 115e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET /* this is a new one as head, expire it */ 116e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET Curl_pipeline_leave_write(conn); /* not in use yet */ 117e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET Curl_expire(conn->send_pipe->head->ptr, 1); 118e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET } 119e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 120e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET#if 0 /* enable for pipeline debugging */ 121e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET print_pipeline(conn); 122e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET#endif 123e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 124e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET return result; 125e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET} 126e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 127e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET/* Move this transfer from the sending list to the receiving list. 128e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 129e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET Pay special attention to the new sending list "leader" as it needs to get 130e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET checked to update what sockets it acts on. 131e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 132e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET*/ 133e3149cc1cf501b46caba8d47652ac90b95c78eacAlex Deymovoid Curl_move_handle_from_send_to_recv_pipe(struct Curl_easy *handle, 134e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET struct connectdata *conn) 135e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET{ 136e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET struct curl_llist_element *curr; 137e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 138e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET curr = conn->send_pipe->head; 139e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET while(curr) { 140e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET if(curr->ptr == handle) { 141e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET Curl_llist_move(conn->send_pipe, curr, 142e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET conn->recv_pipe, conn->recv_pipe->tail); 143e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 144e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET if(conn->send_pipe->head) { 145e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET /* Since there's a new easy handle at the start of the send pipeline, 146e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET set its timeout value to 1ms to make it trigger instantly */ 147e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET Curl_pipeline_leave_write(conn); /* not used now */ 148e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET#ifdef DEBUGBUILD 149e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET infof(conn->data, "%p is at send pipe head B!\n", 150e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET (void *)conn->send_pipe->head->ptr); 151e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET#endif 152e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET Curl_expire(conn->send_pipe->head->ptr, 1); 153e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET } 154e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 155e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET /* The receiver's list is not really interesting here since either this 156e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET handle is now first in the list and we'll deal with it soon, or 157e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET another handle is already first and thus is already taken care of */ 158e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 159e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET break; /* we're done! */ 160e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET } 161e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET curr = curr->next; 162e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET } 163e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET} 164e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 165e3149cc1cf501b46caba8d47652ac90b95c78eacAlex Deymobool Curl_pipeline_site_blacklisted(struct Curl_easy *handle, 166e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET struct connectdata *conn) 167e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET{ 168e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET if(handle->multi) { 169e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET struct curl_llist *blacklist = 170e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET Curl_multi_pipelining_site_bl(handle->multi); 171e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 172e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET if(blacklist) { 173e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET struct curl_llist_element *curr; 174e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 175e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET curr = blacklist->head; 176e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET while(curr) { 177e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET struct site_blacklist_entry *site; 178e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 179e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET site = curr->ptr; 180e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET if(Curl_raw_equal(site->hostname, conn->host.name) && 181e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET site->port == conn->remote_port) { 182e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET infof(handle, "Site %s:%d is pipeline blacklisted\n", 183e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET conn->host.name, conn->remote_port); 184e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET return TRUE; 185e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET } 186e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET curr = curr->next; 187e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET } 188e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET } 189e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET } 190e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET return FALSE; 191e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET} 192e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 193e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNETCURLMcode Curl_pipeline_set_site_blacklist(char **sites, 194e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET struct curl_llist **list_ptr) 195e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET{ 196e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET struct curl_llist *old_list = *list_ptr; 197e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET struct curl_llist *new_list = NULL; 198e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 199e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET if(sites) { 200e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET new_list = Curl_llist_alloc((curl_llist_dtor) site_blacklist_llist_dtor); 201e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET if(!new_list) 202e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET return CURLM_OUT_OF_MEMORY; 203e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 204e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET /* Parse the URLs and populate the list */ 205e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET while(*sites) { 206e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET char *hostname; 207e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET char *port; 208e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET struct site_blacklist_entry *entry; 209e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 210e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET hostname = strdup(*sites); 211e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET if(!hostname) { 212e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET Curl_llist_destroy(new_list, NULL); 213e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET return CURLM_OUT_OF_MEMORY; 214e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET } 215e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 216e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET entry = malloc(sizeof(struct site_blacklist_entry)); 217e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET if(!entry) { 218e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET free(hostname); 219e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET Curl_llist_destroy(new_list, NULL); 220e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET return CURLM_OUT_OF_MEMORY; 221e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET } 222e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 223e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET port = strchr(hostname, ':'); 224e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET if(port) { 225e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET *port = '\0'; 226e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET port++; 227e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET entry->port = (unsigned short)strtol(port, NULL, 10); 228e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET } 229e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET else { 230e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET /* Default port number for HTTP */ 231e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET entry->port = 80; 232e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET } 233e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 234e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET entry->hostname = hostname; 235e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 236e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET if(!Curl_llist_insert_next(new_list, new_list->tail, entry)) { 237e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET site_blacklist_llist_dtor(NULL, entry); 238e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET Curl_llist_destroy(new_list, NULL); 239e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET return CURLM_OUT_OF_MEMORY; 240e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET } 241e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 242e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET sites++; 243e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET } 244e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET } 245e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 246e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET /* Free the old list */ 247e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET if(old_list) { 248e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET Curl_llist_destroy(old_list, NULL); 249e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET } 250e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 251e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET /* This might be NULL if sites == NULL, i.e the blacklist is cleared */ 252e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET *list_ptr = new_list; 253e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 254e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET return CURLM_OK; 255e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET} 256e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 257e3149cc1cf501b46caba8d47652ac90b95c78eacAlex Deymobool Curl_pipeline_server_blacklisted(struct Curl_easy *handle, 258e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET char *server_name) 259e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET{ 260e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET if(handle->multi && server_name) { 261e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET struct curl_llist *blacklist = 262e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET Curl_multi_pipelining_server_bl(handle->multi); 263e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 264e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET if(blacklist) { 265e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET struct curl_llist_element *curr; 266e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 267e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET curr = blacklist->head; 268e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET while(curr) { 269e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET char *bl_server_name; 270e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 271e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET bl_server_name = curr->ptr; 272e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET if(Curl_raw_nequal(bl_server_name, server_name, 273e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET strlen(bl_server_name))) { 274e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET infof(handle, "Server %s is blacklisted\n", server_name); 275e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET return TRUE; 276e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET } 277e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET curr = curr->next; 278e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET } 279e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET } 280e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 281e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET DEBUGF(infof(handle, "Server %s is not blacklisted\n", server_name)); 282e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET } 283e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET return FALSE; 284e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET} 285e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 286e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNETCURLMcode Curl_pipeline_set_server_blacklist(char **servers, 287e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET struct curl_llist **list_ptr) 288e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET{ 289e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET struct curl_llist *old_list = *list_ptr; 290e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET struct curl_llist *new_list = NULL; 291e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 292e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET if(servers) { 293e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET new_list = Curl_llist_alloc((curl_llist_dtor) server_blacklist_llist_dtor); 294e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET if(!new_list) 295e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET return CURLM_OUT_OF_MEMORY; 296e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 297e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET /* Parse the URLs and populate the list */ 298e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET while(*servers) { 299e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET char *server_name; 300e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 301e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET server_name = strdup(*servers); 302e3149cc1cf501b46caba8d47652ac90b95c78eacAlex Deymo if(!server_name) { 303e3149cc1cf501b46caba8d47652ac90b95c78eacAlex Deymo Curl_llist_destroy(new_list, NULL); 304e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET return CURLM_OUT_OF_MEMORY; 305e3149cc1cf501b46caba8d47652ac90b95c78eacAlex Deymo } 306e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 307e3149cc1cf501b46caba8d47652ac90b95c78eacAlex Deymo if(!Curl_llist_insert_next(new_list, new_list->tail, server_name)) { 308e3149cc1cf501b46caba8d47652ac90b95c78eacAlex Deymo Curl_llist_destroy(new_list, NULL); 309e3149cc1cf501b46caba8d47652ac90b95c78eacAlex Deymo Curl_safefree(server_name); 310e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET return CURLM_OUT_OF_MEMORY; 311e3149cc1cf501b46caba8d47652ac90b95c78eacAlex Deymo } 312e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 313e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET servers++; 314e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET } 315e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET } 316e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 317e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET /* Free the old list */ 318e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET if(old_list) { 319e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET Curl_llist_destroy(old_list, NULL); 320e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET } 321e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 322e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET /* This might be NULL if sites == NULL, i.e the blacklist is cleared */ 323e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET *list_ptr = new_list; 324e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 325e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET return CURLM_OK; 326e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET} 327e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 328e3149cc1cf501b46caba8d47652ac90b95c78eacAlex Deymostatic bool pipe_head(struct Curl_easy *data, 329e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET struct curl_llist *pipeline) 330e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET{ 331d15eaac64ca1a7244824d660ea84e8815a23d058Alex Deymo if(pipeline) { 332d15eaac64ca1a7244824d660ea84e8815a23d058Alex Deymo struct curl_llist_element *curr = pipeline->head; 333d15eaac64ca1a7244824d660ea84e8815a23d058Alex Deymo if(curr) 334d15eaac64ca1a7244824d660ea84e8815a23d058Alex Deymo return (curr->ptr == data) ? TRUE : FALSE; 335d15eaac64ca1a7244824d660ea84e8815a23d058Alex Deymo } 336e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET return FALSE; 337e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET} 338e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 339e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET/* returns TRUE if the given handle is head of the recv pipe */ 340e3149cc1cf501b46caba8d47652ac90b95c78eacAlex Deymobool Curl_recvpipe_head(struct Curl_easy *data, 341e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET struct connectdata *conn) 342e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET{ 343e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET return pipe_head(data, conn->recv_pipe); 344e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET} 345e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 346e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET/* returns TRUE if the given handle is head of the send pipe */ 347e3149cc1cf501b46caba8d47652ac90b95c78eacAlex Deymobool Curl_sendpipe_head(struct Curl_easy *data, 348e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET struct connectdata *conn) 349e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET{ 350e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET return pipe_head(data, conn->send_pipe); 351e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET} 352e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 353e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 354e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET/* 355e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET * Check if the write channel is available and this handle as at the head, 356e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET * then grab the channel and return TRUE. 357e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET * 358e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET * If not available, return FALSE. 359e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET */ 360e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 361e3149cc1cf501b46caba8d47652ac90b95c78eacAlex Deymobool Curl_pipeline_checkget_write(struct Curl_easy *data, 362e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET struct connectdata *conn) 363e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET{ 364e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET if(conn->bits.multiplex) 365e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET /* when multiplexing, we can use it at once */ 366e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET return TRUE; 367e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 368e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET if(!conn->writechannel_inuse && Curl_sendpipe_head(data, conn)) { 369e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET /* Grab the channel */ 370e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET conn->writechannel_inuse = TRUE; 371e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET return TRUE; 372e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET } 373e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET return FALSE; 374e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET} 375e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 376e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 377e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET/* 378e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET * Check if the read channel is available and this handle as at the head, then 379e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET * grab the channel and return TRUE. 380e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET * 381e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET * If not available, return FALSE. 382e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET */ 383e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 384e3149cc1cf501b46caba8d47652ac90b95c78eacAlex Deymobool Curl_pipeline_checkget_read(struct Curl_easy *data, 385e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET struct connectdata *conn) 386e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET{ 387e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET if(conn->bits.multiplex) 388e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET /* when multiplexing, we can use it at once */ 389e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET return TRUE; 390e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 391e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET if(!conn->readchannel_inuse && Curl_recvpipe_head(data, conn)) { 392e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET /* Grab the channel */ 393e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET conn->readchannel_inuse = TRUE; 394e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET return TRUE; 395e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET } 396e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET return FALSE; 397e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET} 398e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 399e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET/* 400e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET * The current user of the pipeline write channel gives it up. 401e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET */ 402e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNETvoid Curl_pipeline_leave_write(struct connectdata *conn) 403e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET{ 404e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET conn->writechannel_inuse = FALSE; 405e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET} 406e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 407e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET/* 408e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET * The current user of the pipeline read channel gives it up. 409e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET */ 410e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNETvoid Curl_pipeline_leave_read(struct connectdata *conn) 411e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET{ 412e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET conn->readchannel_inuse = FALSE; 413e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET} 414e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 415e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 416e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET#if 0 417e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNETvoid print_pipeline(struct connectdata *conn) 418e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET{ 419e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET struct curl_llist_element *curr; 420e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET struct connectbundle *cb_ptr; 421e3149cc1cf501b46caba8d47652ac90b95c78eacAlex Deymo struct Curl_easy *data = conn->data; 422e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 423e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET cb_ptr = conn->bundle; 424e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 425e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET if(cb_ptr) { 426e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET curr = cb_ptr->conn_list->head; 427e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET while(curr) { 428e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET conn = curr->ptr; 429e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET infof(data, "- Conn %ld (%p) send_pipe: %zu, recv_pipe: %zu\n", 430e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET conn->connection_id, 431e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET (void *)conn, 432e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET conn->send_pipe->size, 433e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET conn->recv_pipe->size); 434e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET curr = curr->next; 435e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET } 436e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET } 437e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET} 438e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET 439e6cd738ed3716c02557fb3a47515244e949ade39Bertrand SIMONNET#endif 440