1
/***************************************************************************
3
* Project ___| | | | _ \| |
5
* | (__| |_| | _ <| |___
6
* \___|\___/|_| \_\_____|
8
* Copyright (C) 2013, Linus Nielsen Feltzing, <linus@haxx.se>
10
* This software is licensed as described in the file COPYING, which
11
* you should have received as part of this distribution. The terms
12
* are also available at http://curl.haxx.se/docs/copyright.html.
14
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
15
* copies of the Software, and permit persons to whom the Software is
16
* furnished to do so, under the terms of the COPYING file.
18
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19
* KIND, either express or implied.
21
***************************************************************************/
23
#include "curl_setup.h"
25
#include <curl/curl.h>
36
#include "curl_memory.h"
37
/* The last #include file should be: */
40
struct site_blacklist_entry {
45
static void site_blacklist_llist_dtor(void *user, void *element)
47
struct site_blacklist_entry *entry = element;
50
Curl_safefree(entry->hostname);
54
static void server_blacklist_llist_dtor(void *user, void *element)
56
char *server_name = element;
59
Curl_safefree(server_name);
62
bool Curl_pipeline_penalized(struct SessionHandle *data,
63
struct connectdata *conn)
66
bool penalized = FALSE;
67
curl_off_t penalty_size =
68
Curl_multi_content_length_penalty_size(data->multi);
69
curl_off_t chunk_penalty_size =
70
Curl_multi_chunk_length_penalty_size(data->multi);
71
curl_off_t recv_size = -2; /* Make it easy to spot in the log */
73
/* Find the head of the recv pipe, if any */
74
if(conn->recv_pipe && conn->recv_pipe->head) {
75
struct SessionHandle *recv_handle = conn->recv_pipe->head->ptr;
77
recv_size = recv_handle->req.size;
79
if(penalty_size > 0 && recv_size > penalty_size)
83
if(chunk_penalty_size > 0 &&
84
(curl_off_t)conn->chunk.datasize > chunk_penalty_size)
87
infof(data, "Conn: %d (%p) Receive pipe weight: (%d/%d), penalized: %d\n",
88
conn->connection_id, conn, recv_size,
89
conn->chunk.datasize, penalized);
95
CURLcode Curl_add_handle_to_pipeline(struct SessionHandle *handle,
96
struct connectdata *conn)
98
struct curl_llist_element *sendhead = conn->send_pipe->head;
99
struct curl_llist *pipeline;
102
pipeline = conn->send_pipe;
104
infof(conn->data, "Adding handle: conn: %p\n", conn);
105
infof(conn->data, "Adding handle: send: %d\n", conn->send_pipe->size);
106
infof(conn->data, "Adding handle: recv: %d\n", conn->recv_pipe->size);
107
rc = Curl_addHandleToPipeline(handle, pipeline);
109
if(pipeline == conn->send_pipe && sendhead != conn->send_pipe->head) {
110
/* this is a new one as head, expire it */
111
conn->writechannel_inuse = FALSE; /* not in use yet */
113
infof(conn->data, "%p is at send pipe head!\n",
114
conn->send_pipe->head->ptr);
116
Curl_expire(conn->send_pipe->head->ptr, 1);
119
print_pipeline(conn);
124
/* Move this transfer from the sending list to the receiving list.
126
Pay special attention to the new sending list "leader" as it needs to get
127
checked to update what sockets it acts on.
130
void Curl_move_handle_from_send_to_recv_pipe(struct SessionHandle *handle,
131
struct connectdata *conn)
133
struct curl_llist_element *curr;
135
curr = conn->send_pipe->head;
137
if(curr->ptr == handle) {
138
Curl_llist_move(conn->send_pipe, curr,
139
conn->recv_pipe, conn->recv_pipe->tail);
141
if(conn->send_pipe->head) {
142
/* Since there's a new easy handle at the start of the send pipeline,
143
set its timeout value to 1ms to make it trigger instantly */
144
conn->writechannel_inuse = FALSE; /* not used now */
146
infof(conn->data, "%p is at send pipe head B!\n",
147
conn->send_pipe->head->ptr);
149
Curl_expire(conn->send_pipe->head->ptr, 1);
152
/* The receiver's list is not really interesting here since either this
153
handle is now first in the list and we'll deal with it soon, or
154
another handle is already first and thus is already taken care of */
156
break; /* we're done! */
162
bool Curl_pipeline_site_blacklisted(struct SessionHandle *handle,
163
struct connectdata *conn)
166
struct curl_llist *blacklist =
167
Curl_multi_pipelining_site_bl(handle->multi);
170
struct curl_llist_element *curr;
172
curr = blacklist->head;
174
struct site_blacklist_entry *site;
177
if(Curl_raw_equal(site->hostname, conn->host.name) &&
178
site->port == conn->remote_port) {
179
infof(handle, "Site %s:%d is pipeline blacklisted\n",
180
conn->host.name, conn->remote_port);
190
CURLMcode Curl_pipeline_set_site_blacklist(char **sites,
191
struct curl_llist **list_ptr)
193
struct curl_llist *old_list = *list_ptr;
194
struct curl_llist *new_list = NULL;
197
new_list = Curl_llist_alloc((curl_llist_dtor) site_blacklist_llist_dtor);
199
return CURLM_OUT_OF_MEMORY;
201
/* Parse the URLs and populate the list */
205
struct site_blacklist_entry *entry;
207
entry = malloc(sizeof(struct site_blacklist_entry));
209
hostname = strdup(*sites);
211
return CURLM_OUT_OF_MEMORY;
213
port = strchr(hostname, ':');
217
entry->port = (unsigned short)strtol(port, NULL, 10);
220
/* Default port number for HTTP */
224
entry->hostname = hostname;
226
if(!Curl_llist_insert_next(new_list, new_list->tail, entry))
227
return CURLM_OUT_OF_MEMORY;
233
/* Free the old list */
235
Curl_llist_destroy(old_list, NULL);
238
/* This might be NULL if sites == NULL, i.e the blacklist is cleared */
239
*list_ptr = new_list;
244
bool Curl_pipeline_server_blacklisted(struct SessionHandle *handle,
248
struct curl_llist *blacklist =
249
Curl_multi_pipelining_server_bl(handle->multi);
252
struct curl_llist_element *curr;
254
curr = blacklist->head;
256
char *bl_server_name;
258
bl_server_name = curr->ptr;
259
if(Curl_raw_nequal(bl_server_name, server_name,
260
strlen(bl_server_name))) {
261
infof(handle, "Server %s is blacklisted\n", server_name);
268
infof(handle, "Server %s is not blacklisted\n", server_name);
273
CURLMcode Curl_pipeline_set_server_blacklist(char **servers,
274
struct curl_llist **list_ptr)
276
struct curl_llist *old_list = *list_ptr;
277
struct curl_llist *new_list = NULL;
280
new_list = Curl_llist_alloc((curl_llist_dtor) server_blacklist_llist_dtor);
282
return CURLM_OUT_OF_MEMORY;
284
/* Parse the URLs and populate the list */
288
server_name = strdup(*servers);
290
return CURLM_OUT_OF_MEMORY;
292
if(!Curl_llist_insert_next(new_list, new_list->tail, server_name))
293
return CURLM_OUT_OF_MEMORY;
299
/* Free the old list */
301
Curl_llist_destroy(old_list, NULL);
304
/* This might be NULL if sites == NULL, i.e the blacklist is cleared */
305
*list_ptr = new_list;
311
void print_pipeline(struct connectdata *conn)
313
struct curl_llist_element *curr;
314
struct connectbundle *cb_ptr;
315
struct SessionHandle *data = conn->data;
317
cb_ptr = conn->bundle;
320
curr = cb_ptr->conn_list->head;
323
infof(data, "- Conn %d (%p) send_pipe: %d, recv_pipe: %d\n",
326
conn->send_pipe->size,
327
conn->recv_pipe->size);