1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 2013, Linus Nielsen Feltzing, <linus@haxx.se>
9 * Copyright (C) 2013, 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: (%" FORMAT_OFF_T
89 "/%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 infof(conn->data, "Adding handle: conn: %p\n", (void *)conn);
107 infof(conn->data, "Adding handle: send: %d\n", conn->send_pipe->size);
108 infof(conn->data, "Adding handle: recv: %d\n", conn->recv_pipe->size);
109 rc = Curl_addHandleToPipeline(handle, pipeline);
111 if(pipeline == conn->send_pipe && sendhead != conn->send_pipe->head) {
112 /* this is a new one as head, expire it */
113 conn->writechannel_inuse = FALSE; /* not in use yet */
115 infof(conn->data, "%p is at send pipe head!\n",
116 (void *)conn->send_pipe->head->ptr);
118 Curl_expire(conn->send_pipe->head->ptr, 1);
121 print_pipeline(conn);
126 /* Move this transfer from the sending list to the receiving list.
128 Pay special attention to the new sending list "leader" as it needs to get
129 checked to update what sockets it acts on.
132 void Curl_move_handle_from_send_to_recv_pipe(struct SessionHandle *handle,
133 struct connectdata *conn)
135 struct curl_llist_element *curr;
137 curr = conn->send_pipe->head;
139 if(curr->ptr == handle) {
140 Curl_llist_move(conn->send_pipe, curr,
141 conn->recv_pipe, conn->recv_pipe->tail);
143 if(conn->send_pipe->head) {
144 /* Since there's a new easy handle at the start of the send pipeline,
145 set its timeout value to 1ms to make it trigger instantly */
146 conn->writechannel_inuse = FALSE; /* not used now */
148 infof(conn->data, "%p is at send pipe head B!\n",
149 (void *)conn->send_pipe->head->ptr);
151 Curl_expire(conn->send_pipe->head->ptr, 1);
154 /* The receiver's list is not really interesting here since either this
155 handle is now first in the list and we'll deal with it soon, or
156 another handle is already first and thus is already taken care of */
158 break; /* we're done! */
164 bool Curl_pipeline_site_blacklisted(struct SessionHandle *handle,
165 struct connectdata *conn)
168 struct curl_llist *blacklist =
169 Curl_multi_pipelining_site_bl(handle->multi);
172 struct curl_llist_element *curr;
174 curr = blacklist->head;
176 struct site_blacklist_entry *site;
179 if(Curl_raw_equal(site->hostname, conn->host.name) &&
180 site->port == conn->remote_port) {
181 infof(handle, "Site %s:%d is pipeline blacklisted\n",
182 conn->host.name, conn->remote_port);
192 CURLMcode Curl_pipeline_set_site_blacklist(char **sites,
193 struct curl_llist **list_ptr)
195 struct curl_llist *old_list = *list_ptr;
196 struct curl_llist *new_list = NULL;
199 new_list = Curl_llist_alloc((curl_llist_dtor) site_blacklist_llist_dtor);
201 return CURLM_OUT_OF_MEMORY;
203 /* Parse the URLs and populate the list */
207 struct site_blacklist_entry *entry;
209 entry = malloc(sizeof(struct site_blacklist_entry));
211 hostname = strdup(*sites);
213 return CURLM_OUT_OF_MEMORY;
215 port = strchr(hostname, ':');
219 entry->port = (unsigned short)strtol(port, NULL, 10);
222 /* Default port number for HTTP */
226 entry->hostname = hostname;
228 if(!Curl_llist_insert_next(new_list, new_list->tail, entry))
229 return CURLM_OUT_OF_MEMORY;
235 /* Free the old list */
237 Curl_llist_destroy(old_list, NULL);
240 /* This might be NULL if sites == NULL, i.e the blacklist is cleared */
241 *list_ptr = new_list;
246 bool Curl_pipeline_server_blacklisted(struct SessionHandle *handle,
250 struct curl_llist *blacklist =
251 Curl_multi_pipelining_server_bl(handle->multi);
254 struct curl_llist_element *curr;
256 curr = blacklist->head;
258 char *bl_server_name;
260 bl_server_name = curr->ptr;
261 if(Curl_raw_nequal(bl_server_name, server_name,
262 strlen(bl_server_name))) {
263 infof(handle, "Server %s is blacklisted\n", server_name);
270 infof(handle, "Server %s is not blacklisted\n", server_name);
275 CURLMcode Curl_pipeline_set_server_blacklist(char **servers,
276 struct curl_llist **list_ptr)
278 struct curl_llist *old_list = *list_ptr;
279 struct curl_llist *new_list = NULL;
282 new_list = Curl_llist_alloc((curl_llist_dtor) server_blacklist_llist_dtor);
284 return CURLM_OUT_OF_MEMORY;
286 /* Parse the URLs and populate the list */
290 server_name = strdup(*servers);
292 return CURLM_OUT_OF_MEMORY;
294 if(!Curl_llist_insert_next(new_list, new_list->tail, server_name))
295 return CURLM_OUT_OF_MEMORY;
301 /* Free the old list */
303 Curl_llist_destroy(old_list, NULL);
306 /* This might be NULL if sites == NULL, i.e the blacklist is cleared */
307 *list_ptr = new_list;
313 void print_pipeline(struct connectdata *conn)
315 struct curl_llist_element *curr;
316 struct connectbundle *cb_ptr;
317 struct SessionHandle *data = conn->data;
319 cb_ptr = conn->bundle;
322 curr = cb_ptr->conn_list->head;
325 infof(data, "- Conn %ld (%p) send_pipe: %zu, recv_pipe: %zu\n",
328 conn->send_pipe->size,
329 conn->recv_pipe->size);