pipeline.c
Go to the documentation of this file.
1 /***************************************************************************
2  * _ _ ____ _
3  * Project ___| | | | _ \| |
4  * / __| | | | |_) | |
5  * | (__| |_| | _ <| |___
6  * \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 2013, Linus Nielsen Feltzing, <linus@haxx.se>
9  * Copyright (C) 2013 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
10  *
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 https://curl.haxx.se/docs/copyright.html.
14  *
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.
18  *
19  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20  * KIND, either express or implied.
21  *
22  ***************************************************************************/
23 
24 #include "curl_setup.h"
25 
26 #include <curl/curl.h>
27 
28 #include "urldata.h"
29 #include "url.h"
30 #include "progress.h"
31 #include "multiif.h"
32 #include "pipeline.h"
33 #include "sendf.h"
34 #include "strcase.h"
35 
36 #include "curl_memory.h"
37 /* The last #include file should be: */
38 #include "memdebug.h"
39 
42  unsigned short port;
43  char hostname[1];
44 };
45 
46 static void site_blacklist_llist_dtor(void *user, void *element)
47 {
48  struct site_blacklist_entry *entry = element;
49  (void)user;
50  free(entry);
51 }
52 
53 static void server_blacklist_llist_dtor(void *user, void *element)
54 {
55  (void)user;
56  free(element);
57 }
58 
60  struct connectdata *conn)
61 {
62  if(data) {
63  bool penalized = FALSE;
64  curl_off_t penalty_size =
66  curl_off_t chunk_penalty_size =
68  curl_off_t recv_size = -2; /* Make it easy to spot in the log */
69 
70  /* Find the head of the recv pipe, if any */
71  if(conn->recv_pipe.head) {
72  struct Curl_easy *recv_handle = conn->recv_pipe.head->ptr;
73 
74  recv_size = recv_handle->req.size;
75 
76  if(penalty_size > 0 && recv_size > penalty_size)
77  penalized = TRUE;
78  }
79 
80  if(chunk_penalty_size > 0 &&
81  (curl_off_t)conn->chunk.datasize > chunk_penalty_size)
82  penalized = TRUE;
83 
84  infof(data, "Conn: %ld (%p) Receive pipe weight: (%"
85  CURL_FORMAT_CURL_OFF_T "/%zu), penalized: %s\n",
86  conn->connection_id, (void *)conn, recv_size,
87  conn->chunk.datasize, penalized?"TRUE":"FALSE");
88  return penalized;
89  }
90  return FALSE;
91 }
92 
94  struct curl_llist *pipeline)
95 {
96  Curl_llist_insert_next(pipeline, pipeline->tail, data,
97  &data->pipeline_queue);
98  return CURLE_OK;
99 }
100 
101 
103  struct connectdata *conn)
104 {
105  struct curl_llist_element *sendhead = conn->send_pipe.head;
106  struct curl_llist *pipeline;
108 
109  pipeline = &conn->send_pipe;
110 
111  result = addHandleToPipeline(handle, pipeline);
112 
113  if(pipeline == &conn->send_pipe && sendhead != conn->send_pipe.head) {
114  /* this is a new one as head, expire it */
115  Curl_pipeline_leave_write(conn); /* not in use yet */
117  }
118 
119 #if 0 /* enable for pipeline debugging */
120  print_pipeline(conn);
121 #endif
122 
123  return result;
124 }
125 
126 /* Move this transfer from the sending list to the receiving list.
127 
128  Pay special attention to the new sending list "leader" as it needs to get
129  checked to update what sockets it acts on.
130 
131 */
133  struct connectdata *conn)
134 {
135  struct curl_llist_element *curr;
136 
137  curr = conn->send_pipe.head;
138  while(curr) {
139  if(curr->ptr == handle) {
140  Curl_llist_move(&conn->send_pipe, curr,
141  &conn->recv_pipe, conn->recv_pipe.tail);
142 
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  Curl_pipeline_leave_write(conn); /* not used now */
147 #ifdef DEBUGBUILD
148  infof(conn->data, "%p is at send pipe head B!\n",
149  (void *)conn->send_pipe.head->ptr);
150 #endif
152  }
153 
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 */
157 
158  break; /* we're done! */
159  }
160  curr = curr->next;
161  }
162 }
163 
165  struct connectdata *conn)
166 {
167  if(handle->multi) {
168  struct curl_llist *blacklist =
170 
171  if(blacklist) {
172  struct curl_llist_element *curr;
173 
174  curr = blacklist->head;
175  while(curr) {
176  struct site_blacklist_entry *site;
177 
178  site = curr->ptr;
179  if(strcasecompare(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);
183  return TRUE;
184  }
185  curr = curr->next;
186  }
187  }
188  }
189  return FALSE;
190 }
191 
193  struct curl_llist *list)
194 {
195  /* Free the old list */
196  if(list->size)
197  Curl_llist_destroy(list, NULL);
198 
199  if(sites) {
201 
202  /* Parse the URLs and populate the list */
203  while(*sites) {
204  char *port;
205  struct site_blacklist_entry *entry;
206 
207  entry = malloc(sizeof(struct site_blacklist_entry) + strlen(*sites));
208  if(!entry) {
209  Curl_llist_destroy(list, NULL);
210  return CURLM_OUT_OF_MEMORY;
211  }
212  strcpy(entry->hostname, *sites);
213 
214  port = strchr(entry->hostname, ':');
215  if(port) {
216  *port = '\0';
217  port++;
218  entry->port = (unsigned short)strtol(port, NULL, 10);
219  }
220  else {
221  /* Default port number for HTTP */
222  entry->port = 80;
223  }
224 
225  Curl_llist_insert_next(list, list->tail, entry, &entry->list);
226  sites++;
227  }
228  }
229 
230  return CURLM_OK;
231 }
232 
235  char server_name[1];
236 };
237 
239  char *server_name)
240 {
241  if(handle->multi && server_name) {
242  struct curl_llist *list =
244 
245  struct curl_llist_element *e = list->head;
246  while(e) {
247  struct blacklist_node *bl = (struct blacklist_node *)e;
248  if(strncasecompare(bl->server_name, server_name,
249  strlen(bl->server_name))) {
250  infof(handle, "Server %s is blacklisted\n", server_name);
251  return TRUE;
252  }
253  e = e->next;
254  }
255 
256  DEBUGF(infof(handle, "Server %s is not blacklisted\n", server_name));
257  }
258  return FALSE;
259 }
260 
262  struct curl_llist *list)
263 {
264  /* Free the old list */
265  if(list->size)
266  Curl_llist_destroy(list, NULL);
267 
268  if(servers) {
270 
271  /* Parse the URLs and populate the list */
272  while(*servers) {
273  struct blacklist_node *n;
274  size_t len = strlen(*servers);
275 
276  n = malloc(sizeof(struct blacklist_node) + len);
277  if(!n) {
278  Curl_llist_destroy(list, NULL);
279  return CURLM_OUT_OF_MEMORY;
280  }
281  strcpy(n->server_name, *servers);
282 
283  Curl_llist_insert_next(list, list->tail, n, &n->list);
284  servers++;
285  }
286  }
287 
288 
289  return CURLM_OK;
290 }
291 
292 static bool pipe_head(struct Curl_easy *data,
293  struct curl_llist *pipeline)
294 {
295  if(pipeline) {
296  struct curl_llist_element *curr = pipeline->head;
297  if(curr)
298  return (curr->ptr == data) ? TRUE : FALSE;
299  }
300  return FALSE;
301 }
302 
303 /* returns TRUE if the given handle is head of the recv pipe */
305  struct connectdata *conn)
306 {
307  return pipe_head(data, &conn->recv_pipe);
308 }
309 
310 /* returns TRUE if the given handle is head of the send pipe */
312  struct connectdata *conn)
313 {
314  return pipe_head(data, &conn->send_pipe);
315 }
316 
317 
318 /*
319  * Check if the write channel is available and this handle as at the head,
320  * then grab the channel and return TRUE.
321  *
322  * If not available, return FALSE.
323  */
324 
326  struct connectdata *conn)
327 {
328  if(conn->bits.multiplex)
329  /* when multiplexing, we can use it at once */
330  return TRUE;
331 
332  if(!conn->writechannel_inuse && Curl_sendpipe_head(data, conn)) {
333  /* Grab the channel */
334  conn->writechannel_inuse = TRUE;
335  return TRUE;
336  }
337  return FALSE;
338 }
339 
340 
341 /*
342  * Check if the read channel is available and this handle as at the head, then
343  * grab the channel and return TRUE.
344  *
345  * If not available, return FALSE.
346  */
347 
349  struct connectdata *conn)
350 {
351  if(conn->bits.multiplex)
352  /* when multiplexing, we can use it at once */
353  return TRUE;
354 
355  if(!conn->readchannel_inuse && Curl_recvpipe_head(data, conn)) {
356  /* Grab the channel */
357  conn->readchannel_inuse = TRUE;
358  return TRUE;
359  }
360  return FALSE;
361 }
362 
363 /*
364  * The current user of the pipeline write channel gives it up.
365  */
367 {
368  conn->writechannel_inuse = FALSE;
369 }
370 
371 /*
372  * The current user of the pipeline read channel gives it up.
373  */
375 {
376  conn->readchannel_inuse = FALSE;
377 }
378 
379 
380 #if 0
381 void print_pipeline(struct connectdata *conn)
382 {
383  struct curl_llist_element *curr;
384  struct connectbundle *cb_ptr;
385  struct Curl_easy *data = conn->data;
386 
387  cb_ptr = conn->bundle;
388 
389  if(cb_ptr) {
390  curr = cb_ptr->conn_list->head;
391  while(curr) {
392  conn = curr->ptr;
393  infof(data, "- Conn %ld (%p) send_pipe: %zu, recv_pipe: %zu\n",
394  conn->connection_id,
395  (void *)conn,
396  conn->send_pipe->size,
397  conn->recv_pipe->size);
398  curr = curr->next;
399  }
400  }
401 }
402 
403 #endif
#define free(ptr)
Definition: curl_memory.h:130
static void site_blacklist_llist_dtor(void *user, void *element)
Definition: pipeline.c:46
struct curl_llist recv_pipe
Definition: urldata.h:957
struct ConnectBits bits
Definition: urldata.h:893
static CURLcode addHandleToPipeline(struct Curl_easy *data, struct curl_llist *pipeline)
Definition: pipeline.c:93
unsigned short port
Definition: pipeline.c:42
curl_off_t size
Definition: urldata.h:519
bool Curl_pipeline_site_blacklisted(struct Curl_easy *handle, struct connectdata *conn)
Definition: pipeline.c:164
void(* curl_llist_dtor)(void *, void *)
Definition: llist.h:28
struct curl_llist send_pipe
Definition: urldata.h:955
CURLcode Curl_add_handle_to_pipeline(struct Curl_easy *handle, struct connectdata *conn)
Definition: pipeline.c:102
CURLMcode Curl_pipeline_set_site_blacklist(char **sites, struct curl_llist *list)
Definition: pipeline.c:192
static char server_name[50]
Definition: web_server.c:70
struct curl_llist_element * tail
Definition: llist.h:38
bool Curl_pipeline_checkget_read(struct Curl_easy *data, struct connectdata *conn)
Definition: pipeline.c:348
struct Curl_multi * multi
Definition: urldata.h:1754
CURLcode
Definition: curl.h:454
bool Curl_pipeline_checkget_write(struct Curl_easy *data, struct connectdata *conn)
Definition: pipeline.c:325
void Curl_llist_init(struct curl_llist *l, curl_llist_dtor dtor)
Definition: llist.c:37
struct Curl_chunker chunk
Definition: urldata.h:798
struct curl_llist_element list
Definition: pipeline.c:41
CURLMcode Curl_pipeline_set_server_blacklist(char **servers, struct curl_llist *list)
Definition: pipeline.c:261
struct hostname host
Definition: urldata.h:833
curl_off_t Curl_multi_chunk_length_penalty_size(struct Curl_multi *multi)
Definition: multi.c:3074
Definition: pipeline.c:40
#define strcasecompare(a, b)
Definition: strcase.h:35
#define malloc(size)
Definition: curl_memory.h:124
void Curl_llist_move(struct curl_llist *list, struct curl_llist_element *e, struct curl_llist *to_list, struct curl_llist_element *to_e)
Definition: llist.c:147
char * name
Definition: urldata.h:444
UNITTEST_START int result
Definition: unit1304.c:49
static void server_blacklist_llist_dtor(void *user, void *element)
Definition: pipeline.c:53
bool Curl_recvpipe_head(struct Curl_easy *data, struct connectdata *conn)
Definition: pipeline.c:304
size_t len
Definition: curl_sasl.c:55
bool Curl_sendpipe_head(struct Curl_easy *data, struct connectdata *conn)
Definition: pipeline.c:311
void Curl_move_handle_from_send_to_recv_pipe(struct Curl_easy *handle, struct connectdata *conn)
Definition: pipeline.c:132
#define FALSE
bool readchannel_inuse
Definition: urldata.h:951
struct SingleRequest req
Definition: urldata.h:1761
size_t size
Definition: llist.h:40
void * ptr
Definition: llist.h:31
#define strncasecompare(a, b, c)
Definition: strcase.h:36
bool writechannel_inuse
Definition: urldata.h:953
void Curl_pipeline_leave_read(struct connectdata *conn)
Definition: pipeline.c:374
long connection_id
Definition: urldata.h:809
static bool pipe_head(struct Curl_easy *data, struct curl_llist *pipeline)
Definition: pipeline.c:292
CURL_TYPEOF_CURL_OFF_T curl_off_t
Definition: system.h:420
void Curl_pipeline_leave_write(struct connectdata *conn)
Definition: pipeline.c:366
Definition: curl.h:455
struct curl_llist_element * head
Definition: llist.h:37
bool Curl_pipeline_server_blacklisted(struct Curl_easy *handle, char *server_name)
Definition: pipeline.c:238
char hostname[1]
Definition: pipeline.c:43
CURLMcode
Definition: multi.h:61
char server_name[1]
Definition: pipeline.c:235
void Curl_llist_destroy(struct curl_llist *list, void *user)
Definition: llist.c:130
struct connectbundle * bundle
Definition: urldata.h:1026
struct curl_llist * Curl_multi_pipelining_server_bl(struct Curl_multi *multi)
Definition: multi.c:3084
#define infof
Definition: sendf.h:44
curl_off_t Curl_multi_content_length_penalty_size(struct Curl_multi *multi)
Definition: multi.c:3069
Definition: multi.h:64
void Curl_llist_insert_next(struct curl_llist *list, struct curl_llist_element *e, const void *p, struct curl_llist_element *ne)
Definition: llist.c:57
void Curl_expire(struct Curl_easy *data, time_t milli, expire_id id)
Definition: multi.c:2930
#define TRUE
struct curl_llist conn_list
Definition: conncache.h:41
bool multiplex
Definition: urldata.h:431
bool Curl_pipeline_penalized(struct Curl_easy *data, struct connectdata *conn)
Definition: pipeline.c:59
curl_off_t datasize
Definition: http_chunks.h:86
struct curl_llist * Curl_multi_pipelining_site_bl(struct Curl_multi *multi)
Definition: multi.c:3079
Definition: debug.c:29
int remote_port
Definition: urldata.h:842
struct curl_llist_element pipeline_queue
Definition: urldata.h:1739
struct curl_llist_element list
Definition: pipeline.c:234
struct curl_llist_element * next
Definition: llist.h:33
#define CURL_FORMAT_CURL_OFF_T
Definition: system.h:373
#define DEBUGF(x)
struct Curl_easy * data
Definition: urldata.h:791


rc_tagdetect_client
Author(s): Monika Florek-Jasinska , Raphael Schaller
autogenerated on Sat Feb 13 2021 03:42:16