~ubuntu-branches/ubuntu/vivid/curl/vivid

« back to all changes in this revision

Viewing changes to lib/pipeline.c

  • Committer: Package Import Robot
  • Author(s): Sebastien Bacher
  • Date: 2013-05-07 12:16:37 UTC
  • mfrom: (3.4.37 sid)
  • Revision ID: package-import@ubuntu.com-20130507121637-9t3i98qgsyr9dw5d
Tags: 7.30.0-1ubuntu1
* Resynchronize on Debian. Remaining changes:
  - Drop dependencies not in main:
    + Build-Depends: Drop stunnel4 and libssh2-1-dev.
    + Drop libssh2-1-dev from binary package Depends.
  - Add new libcurl3-udeb package.
  - Add new curl-udeb package.
* Add warning to debian/patches/series.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
 *                                  _   _ ____  _
 
3
 *  Project                     ___| | | |  _ \| |
 
4
 *                             / __| | | | |_) | |
 
5
 *                            | (__| |_| |  _ <| |___
 
6
 *                             \___|\___/|_| \_\_____|
 
7
 *
 
8
 * Copyright (C) 2013, Linus Nielsen Feltzing, <linus@haxx.se>
 
9
 *
 
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.
 
13
 *
 
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.
 
17
 *
 
18
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 
19
 * KIND, either express or implied.
 
20
 *
 
21
 ***************************************************************************/
 
22
 
 
23
#include "curl_setup.h"
 
24
 
 
25
#include <curl/curl.h>
 
26
 
 
27
#include "urldata.h"
 
28
#include "url.h"
 
29
#include "progress.h"
 
30
#include "multiif.h"
 
31
#include "pipeline.h"
 
32
#include "sendf.h"
 
33
#include "rawstr.h"
 
34
#include "bundles.h"
 
35
 
 
36
#include "curl_memory.h"
 
37
/* The last #include file should be: */
 
38
#include "memdebug.h"
 
39
 
 
40
struct site_blacklist_entry {
 
41
  char *hostname;
 
42
  unsigned short port;
 
43
};
 
44
 
 
45
static void site_blacklist_llist_dtor(void *user, void *element)
 
46
{
 
47
  struct site_blacklist_entry *entry = element;
 
48
  (void)user;
 
49
 
 
50
  Curl_safefree(entry->hostname);
 
51
  Curl_safefree(entry);
 
52
}
 
53
 
 
54
static void server_blacklist_llist_dtor(void *user, void *element)
 
55
{
 
56
  char *server_name = element;
 
57
  (void)user;
 
58
 
 
59
  Curl_safefree(server_name);
 
60
}
 
61
 
 
62
bool Curl_pipeline_penalized(struct SessionHandle *data,
 
63
                             struct connectdata *conn)
 
64
{
 
65
  if(data) {
 
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 */
 
72
 
 
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;
 
76
 
 
77
      recv_size = recv_handle->req.size;
 
78
 
 
79
      if(penalty_size > 0 && recv_size > penalty_size)
 
80
        penalized = TRUE;
 
81
    }
 
82
 
 
83
    if(chunk_penalty_size > 0 &&
 
84
       (curl_off_t)conn->chunk.datasize > chunk_penalty_size)
 
85
      penalized = TRUE;
 
86
 
 
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);
 
90
    return penalized;
 
91
  }
 
92
  return FALSE;
 
93
}
 
94
 
 
95
CURLcode Curl_add_handle_to_pipeline(struct SessionHandle *handle,
 
96
                                     struct connectdata *conn)
 
97
{
 
98
  struct curl_llist_element *sendhead = conn->send_pipe->head;
 
99
  struct curl_llist *pipeline;
 
100
  CURLcode rc;
 
101
 
 
102
  pipeline = conn->send_pipe;
 
103
 
 
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);
 
108
 
 
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 */
 
112
#ifdef DEBUGBUILD
 
113
    infof(conn->data, "%p is at send pipe head!\n",
 
114
          conn->send_pipe->head->ptr);
 
115
#endif
 
116
    Curl_expire(conn->send_pipe->head->ptr, 1);
 
117
  }
 
118
 
 
119
  print_pipeline(conn);
 
120
 
 
121
  return rc;
 
122
}
 
123
 
 
124
/* Move this transfer from the sending list to the receiving list.
 
125
 
 
126
   Pay special attention to the new sending list "leader" as it needs to get
 
127
   checked to update what sockets it acts on.
 
128
 
 
129
*/
 
130
void Curl_move_handle_from_send_to_recv_pipe(struct SessionHandle *handle,
 
131
                                             struct connectdata *conn)
 
132
{
 
133
  struct curl_llist_element *curr;
 
134
 
 
135
  curr = conn->send_pipe->head;
 
136
  while(curr) {
 
137
    if(curr->ptr == handle) {
 
138
      Curl_llist_move(conn->send_pipe, curr,
 
139
                      conn->recv_pipe, conn->recv_pipe->tail);
 
140
 
 
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 */
 
145
#ifdef DEBUGBUILD
 
146
        infof(conn->data, "%p is at send pipe head B!\n",
 
147
              conn->send_pipe->head->ptr);
 
148
#endif
 
149
        Curl_expire(conn->send_pipe->head->ptr, 1);
 
150
      }
 
151
 
 
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 */
 
155
 
 
156
      break; /* we're done! */
 
157
    }
 
158
    curr = curr->next;
 
159
  }
 
160
}
 
161
 
 
162
bool Curl_pipeline_site_blacklisted(struct SessionHandle *handle,
 
163
                                    struct connectdata *conn)
 
164
{
 
165
  if(handle->multi) {
 
166
    struct curl_llist *blacklist =
 
167
      Curl_multi_pipelining_site_bl(handle->multi);
 
168
 
 
169
    if(blacklist) {
 
170
      struct curl_llist_element *curr;
 
171
 
 
172
      curr = blacklist->head;
 
173
      while(curr) {
 
174
        struct site_blacklist_entry *site;
 
175
 
 
176
        site = curr->ptr;
 
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);
 
181
          return TRUE;
 
182
        }
 
183
        curr = curr->next;
 
184
      }
 
185
    }
 
186
  }
 
187
  return FALSE;
 
188
}
 
189
 
 
190
CURLMcode Curl_pipeline_set_site_blacklist(char **sites,
 
191
                                           struct curl_llist **list_ptr)
 
192
{
 
193
  struct curl_llist *old_list = *list_ptr;
 
194
  struct curl_llist *new_list = NULL;
 
195
 
 
196
  if(sites) {
 
197
    new_list = Curl_llist_alloc((curl_llist_dtor) site_blacklist_llist_dtor);
 
198
    if(!new_list)
 
199
      return CURLM_OUT_OF_MEMORY;
 
200
 
 
201
    /* Parse the URLs and populate the list */
 
202
    while(*sites) {
 
203
      char *hostname;
 
204
      char *port;
 
205
      struct site_blacklist_entry *entry;
 
206
 
 
207
      entry = malloc(sizeof(struct site_blacklist_entry));
 
208
 
 
209
      hostname = strdup(*sites);
 
210
      if(!hostname)
 
211
        return CURLM_OUT_OF_MEMORY;
 
212
 
 
213
      port = strchr(hostname, ':');
 
214
      if(port) {
 
215
        *port = '\0';
 
216
        port++;
 
217
        entry->port = (unsigned short)strtol(port, NULL, 10);
 
218
      }
 
219
      else {
 
220
        /* Default port number for HTTP */
 
221
        entry->port = 80;
 
222
      }
 
223
 
 
224
      entry->hostname = hostname;
 
225
 
 
226
      if(!Curl_llist_insert_next(new_list, new_list->tail, entry))
 
227
        return CURLM_OUT_OF_MEMORY;
 
228
 
 
229
      sites++;
 
230
    }
 
231
  }
 
232
 
 
233
  /* Free the old list */
 
234
  if(old_list) {
 
235
    Curl_llist_destroy(old_list, NULL);
 
236
  }
 
237
 
 
238
  /* This might be NULL if sites == NULL, i.e the blacklist is cleared */
 
239
  *list_ptr = new_list;
 
240
 
 
241
  return CURLM_OK;
 
242
}
 
243
 
 
244
bool Curl_pipeline_server_blacklisted(struct SessionHandle *handle,
 
245
                                      char *server_name)
 
246
{
 
247
  if(handle->multi) {
 
248
    struct curl_llist *blacklist =
 
249
      Curl_multi_pipelining_server_bl(handle->multi);
 
250
 
 
251
    if(blacklist) {
 
252
      struct curl_llist_element *curr;
 
253
 
 
254
      curr = blacklist->head;
 
255
      while(curr) {
 
256
        char *bl_server_name;
 
257
 
 
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);
 
262
          return TRUE;
 
263
        }
 
264
        curr = curr->next;
 
265
      }
 
266
    }
 
267
 
 
268
    infof(handle, "Server %s is not blacklisted\n", server_name);
 
269
  }
 
270
  return FALSE;
 
271
}
 
272
 
 
273
CURLMcode Curl_pipeline_set_server_blacklist(char **servers,
 
274
                                             struct curl_llist **list_ptr)
 
275
{
 
276
  struct curl_llist *old_list = *list_ptr;
 
277
  struct curl_llist *new_list = NULL;
 
278
 
 
279
  if(servers) {
 
280
    new_list = Curl_llist_alloc((curl_llist_dtor) server_blacklist_llist_dtor);
 
281
    if(!new_list)
 
282
      return CURLM_OUT_OF_MEMORY;
 
283
 
 
284
    /* Parse the URLs and populate the list */
 
285
    while(*servers) {
 
286
      char *server_name;
 
287
 
 
288
      server_name = strdup(*servers);
 
289
      if(!server_name)
 
290
        return CURLM_OUT_OF_MEMORY;
 
291
 
 
292
      if(!Curl_llist_insert_next(new_list, new_list->tail, server_name))
 
293
        return CURLM_OUT_OF_MEMORY;
 
294
 
 
295
      servers++;
 
296
    }
 
297
  }
 
298
 
 
299
  /* Free the old list */
 
300
  if(old_list) {
 
301
    Curl_llist_destroy(old_list, NULL);
 
302
  }
 
303
 
 
304
  /* This might be NULL if sites == NULL, i.e the blacklist is cleared */
 
305
  *list_ptr = new_list;
 
306
 
 
307
  return CURLM_OK;
 
308
}
 
309
 
 
310
 
 
311
void print_pipeline(struct connectdata *conn)
 
312
{
 
313
  struct curl_llist_element *curr;
 
314
  struct connectbundle *cb_ptr;
 
315
  struct SessionHandle *data = conn->data;
 
316
 
 
317
  cb_ptr = conn->bundle;
 
318
 
 
319
  if(cb_ptr) {
 
320
    curr = cb_ptr->conn_list->head;
 
321
    while(curr) {
 
322
      conn = curr->ptr;
 
323
      infof(data, "- Conn %d (%p) send_pipe: %d, recv_pipe: %d\n",
 
324
            conn->connection_id,
 
325
            conn,
 
326
            conn->send_pipe->size,
 
327
            conn->recv_pipe->size);
 
328
      curr = curr->next;
 
329
    }
 
330
  }
 
331
}