1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 2013, Linus Nielsen Feltzing, <linus@haxx.se>
9 * Copyright (C) 2013-2014, Daniel Stenberg, <daniel@haxx.se>, et al.
11 * This software is licensed as described in the file COPYING, which
12 * you should have received as part of this distribution. The terms
13 * are also available at http://curl.haxx.se/docs/copyright.html.
15 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
16 * copies of the Software, and permit persons to whom the Software is
17 * furnished to do so, under the terms of the COPYING file.
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
22 ***************************************************************************/
24 #include "curl_setup.h"
26 #include <curl/curl.h>
37 #include "curl_memory.h"
38 /* The last #include file should be: */
41 struct site_blacklist_entry {
46 static void site_blacklist_llist_dtor(void *user, void *element)
48 struct site_blacklist_entry *entry = element;
51 Curl_safefree(entry->hostname);
55 static void server_blacklist_llist_dtor(void *user, void *element)
57 char *server_name = element;
60 Curl_safefree(server_name);
63 bool Curl_pipeline_penalized(struct SessionHandle *data,
64 struct connectdata *conn)
67 bool penalized = FALSE;
68 curl_off_t penalty_size =
69 Curl_multi_content_length_penalty_size(data->multi);
70 curl_off_t chunk_penalty_size =
71 Curl_multi_chunk_length_penalty_size(data->multi);
72 curl_off_t recv_size = -2; /* Make it easy to spot in the log */
74 /* Find the head of the recv pipe, if any */
75 if(conn->recv_pipe && conn->recv_pipe->head) {
76 struct SessionHandle *recv_handle = conn->recv_pipe->head->ptr;
78 recv_size = recv_handle->req.size;
80 if(penalty_size > 0 && recv_size > penalty_size)
84 if(chunk_penalty_size > 0 &&
85 (curl_off_t)conn->chunk.datasize > chunk_penalty_size)
88 infof(data, "Conn: %ld (%p) Receive pipe weight: (%"
89 CURL_FORMAT_CURL_OFF_T "/%zu), penalized: %s\n",
90 conn->connection_id, (void *)conn, recv_size,
91 conn->chunk.datasize, penalized?"TRUE":"FALSE");
97 CURLcode Curl_add_handle_to_pipeline(struct SessionHandle *handle,
98 struct connectdata *conn)
100 struct curl_llist_element *sendhead = conn->send_pipe->head;
101 struct curl_llist *pipeline;
104 pipeline = conn->send_pipe;
106 rc = Curl_addHandleToPipeline(handle, pipeline);
108 if(pipeline == conn->send_pipe && sendhead != conn->send_pipe->head) {
109 /* this is a new one as head, expire it */
110 conn->writechannel_inuse = FALSE; /* not in use yet */
111 Curl_expire(conn->send_pipe->head->ptr, 1);
114 #if 0 /* enable for pipeline debugging */
115 print_pipeline(conn);
121 /* Move this transfer from the sending list to the receiving list.
123 Pay special attention to the new sending list "leader" as it needs to get
124 checked to update what sockets it acts on.
127 void Curl_move_handle_from_send_to_recv_pipe(struct SessionHandle *handle,
128 struct connectdata *conn)
130 struct curl_llist_element *curr;
132 curr = conn->send_pipe->head;
134 if(curr->ptr == handle) {
135 Curl_llist_move(conn->send_pipe, curr,
136 conn->recv_pipe, conn->recv_pipe->tail);
138 if(conn->send_pipe->head) {
139 /* Since there's a new easy handle at the start of the send pipeline,
140 set its timeout value to 1ms to make it trigger instantly */
141 conn->writechannel_inuse = FALSE; /* not used now */
143 infof(conn->data, "%p is at send pipe head B!\n",
144 (void *)conn->send_pipe->head->ptr);
146 Curl_expire(conn->send_pipe->head->ptr, 1);
149 /* The receiver's list is not really interesting here since either this
150 handle is now first in the list and we'll deal with it soon, or
151 another handle is already first and thus is already taken care of */
153 break; /* we're done! */
159 bool Curl_pipeline_site_blacklisted(struct SessionHandle *handle,
160 struct connectdata *conn)
163 struct curl_llist *blacklist =
164 Curl_multi_pipelining_site_bl(handle->multi);
167 struct curl_llist_element *curr;
169 curr = blacklist->head;
171 struct site_blacklist_entry *site;
174 if(Curl_raw_equal(site->hostname, conn->host.name) &&
175 site->port == conn->remote_port) {
176 infof(handle, "Site %s:%d is pipeline blacklisted\n",
177 conn->host.name, conn->remote_port);
187 CURLMcode Curl_pipeline_set_site_blacklist(char **sites,
188 struct curl_llist **list_ptr)
190 struct curl_llist *old_list = *list_ptr;
191 struct curl_llist *new_list = NULL;
194 new_list = Curl_llist_alloc((curl_llist_dtor) site_blacklist_llist_dtor);
196 return CURLM_OUT_OF_MEMORY;
198 /* Parse the URLs and populate the list */
202 struct site_blacklist_entry *entry;
204 hostname = strdup(*sites);
206 Curl_llist_destroy(new_list, NULL);
207 return CURLM_OUT_OF_MEMORY;
210 entry = malloc(sizeof(struct site_blacklist_entry));
213 Curl_llist_destroy(new_list, NULL);
214 return CURLM_OUT_OF_MEMORY;
217 port = strchr(hostname, ':');
221 entry->port = (unsigned short)strtol(port, NULL, 10);
224 /* Default port number for HTTP */
228 entry->hostname = hostname;
230 if(!Curl_llist_insert_next(new_list, new_list->tail, entry)) {
231 site_blacklist_llist_dtor(NULL, entry);
232 Curl_llist_destroy(new_list, NULL);
233 return CURLM_OUT_OF_MEMORY;
240 /* Free the old list */
242 Curl_llist_destroy(old_list, NULL);
245 /* This might be NULL if sites == NULL, i.e the blacklist is cleared */
246 *list_ptr = new_list;
251 bool Curl_pipeline_server_blacklisted(struct SessionHandle *handle,
255 struct curl_llist *blacklist =
256 Curl_multi_pipelining_server_bl(handle->multi);
259 struct curl_llist_element *curr;
261 curr = blacklist->head;
263 char *bl_server_name;
265 bl_server_name = curr->ptr;
266 if(Curl_raw_nequal(bl_server_name, server_name,
267 strlen(bl_server_name))) {
268 infof(handle, "Server %s is blacklisted\n", server_name);
275 infof(handle, "Server %s is not blacklisted\n", server_name);
280 CURLMcode Curl_pipeline_set_server_blacklist(char **servers,
281 struct curl_llist **list_ptr)
283 struct curl_llist *old_list = *list_ptr;
284 struct curl_llist *new_list = NULL;
287 new_list = Curl_llist_alloc((curl_llist_dtor) server_blacklist_llist_dtor);
289 return CURLM_OUT_OF_MEMORY;
291 /* Parse the URLs and populate the list */
295 server_name = strdup(*servers);
297 return CURLM_OUT_OF_MEMORY;
299 if(!Curl_llist_insert_next(new_list, new_list->tail, server_name))
300 return CURLM_OUT_OF_MEMORY;
306 /* Free the old list */
308 Curl_llist_destroy(old_list, NULL);
311 /* This might be NULL if sites == NULL, i.e the blacklist is cleared */
312 *list_ptr = new_list;
318 void print_pipeline(struct connectdata *conn)
320 struct curl_llist_element *curr;
321 struct connectbundle *cb_ptr;
322 struct SessionHandle *data = conn->data;
324 cb_ptr = conn->bundle;
327 curr = cb_ptr->conn_list->head;
330 infof(data, "- Conn %ld (%p) send_pipe: %zu, recv_pipe: %zu\n",
333 conn->send_pipe->size,
334 conn->recv_pipe->size);