00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "curl_setup.h"
00025
00026 #include <curl/curl.h>
00027
00028 #include "urldata.h"
00029 #include "url.h"
00030 #include "progress.h"
00031 #include "multiif.h"
00032 #include "pipeline.h"
00033 #include "sendf.h"
00034 #include "strcase.h"
00035
00036 #include "curl_memory.h"
00037
00038 #include "memdebug.h"
00039
00040 struct site_blacklist_entry {
00041 char *hostname;
00042 unsigned short port;
00043 };
00044
00045 static void site_blacklist_llist_dtor(void *user, void *element)
00046 {
00047 struct site_blacklist_entry *entry = element;
00048 (void)user;
00049
00050 Curl_safefree(entry->hostname);
00051 free(entry);
00052 }
00053
00054 static void server_blacklist_llist_dtor(void *user, void *element)
00055 {
00056 (void)user;
00057 free(element);
00058 }
00059
00060 bool Curl_pipeline_penalized(struct Curl_easy *data,
00061 struct connectdata *conn)
00062 {
00063 if(data) {
00064 bool penalized = FALSE;
00065 curl_off_t penalty_size =
00066 Curl_multi_content_length_penalty_size(data->multi);
00067 curl_off_t chunk_penalty_size =
00068 Curl_multi_chunk_length_penalty_size(data->multi);
00069 curl_off_t recv_size = -2;
00070
00071
00072 if(conn->recv_pipe && conn->recv_pipe->head) {
00073 struct Curl_easy *recv_handle = conn->recv_pipe->head->ptr;
00074
00075 recv_size = recv_handle->req.size;
00076
00077 if(penalty_size > 0 && recv_size > penalty_size)
00078 penalized = TRUE;
00079 }
00080
00081 if(chunk_penalty_size > 0 &&
00082 (curl_off_t)conn->chunk.datasize > chunk_penalty_size)
00083 penalized = TRUE;
00084
00085 infof(data, "Conn: %ld (%p) Receive pipe weight: (%"
00086 CURL_FORMAT_CURL_OFF_T "/%zu), penalized: %s\n",
00087 conn->connection_id, (void *)conn, recv_size,
00088 conn->chunk.datasize, penalized?"TRUE":"FALSE");
00089 return penalized;
00090 }
00091 return FALSE;
00092 }
00093
00094 static CURLcode addHandleToPipeline(struct Curl_easy *data,
00095 struct curl_llist *pipeline)
00096 {
00097 if(!Curl_llist_insert_next(pipeline, pipeline->tail, data))
00098 return CURLE_OUT_OF_MEMORY;
00099 return CURLE_OK;
00100 }
00101
00102
00103 CURLcode Curl_add_handle_to_pipeline(struct Curl_easy *handle,
00104 struct connectdata *conn)
00105 {
00106 struct curl_llist_element *sendhead = conn->send_pipe->head;
00107 struct curl_llist *pipeline;
00108 CURLcode result;
00109
00110 pipeline = conn->send_pipe;
00111
00112 result = addHandleToPipeline(handle, pipeline);
00113
00114 if(pipeline == conn->send_pipe && sendhead != conn->send_pipe->head) {
00115
00116 Curl_pipeline_leave_write(conn);
00117 Curl_expire(conn->send_pipe->head->ptr, 0);
00118 }
00119
00120 #if 0
00121 print_pipeline(conn);
00122 #endif
00123
00124 return result;
00125 }
00126
00127
00128
00129
00130
00131
00132
00133 void Curl_move_handle_from_send_to_recv_pipe(struct Curl_easy *handle,
00134 struct connectdata *conn)
00135 {
00136 struct curl_llist_element *curr;
00137
00138 curr = conn->send_pipe->head;
00139 while(curr) {
00140 if(curr->ptr == handle) {
00141 Curl_llist_move(conn->send_pipe, curr,
00142 conn->recv_pipe, conn->recv_pipe->tail);
00143
00144 if(conn->send_pipe->head) {
00145
00146
00147 Curl_pipeline_leave_write(conn);
00148 #ifdef DEBUGBUILD
00149 infof(conn->data, "%p is at send pipe head B!\n",
00150 (void *)conn->send_pipe->head->ptr);
00151 #endif
00152 Curl_expire(conn->send_pipe->head->ptr, 0);
00153 }
00154
00155
00156
00157
00158
00159 break;
00160 }
00161 curr = curr->next;
00162 }
00163 }
00164
00165 bool Curl_pipeline_site_blacklisted(struct Curl_easy *handle,
00166 struct connectdata *conn)
00167 {
00168 if(handle->multi) {
00169 struct curl_llist *blacklist =
00170 Curl_multi_pipelining_site_bl(handle->multi);
00171
00172 if(blacklist) {
00173 struct curl_llist_element *curr;
00174
00175 curr = blacklist->head;
00176 while(curr) {
00177 struct site_blacklist_entry *site;
00178
00179 site = curr->ptr;
00180 if(strcasecompare(site->hostname, conn->host.name) &&
00181 site->port == conn->remote_port) {
00182 infof(handle, "Site %s:%d is pipeline blacklisted\n",
00183 conn->host.name, conn->remote_port);
00184 return TRUE;
00185 }
00186 curr = curr->next;
00187 }
00188 }
00189 }
00190 return FALSE;
00191 }
00192
00193 CURLMcode Curl_pipeline_set_site_blacklist(char **sites,
00194 struct curl_llist **list_ptr)
00195 {
00196 struct curl_llist *old_list = *list_ptr;
00197 struct curl_llist *new_list = NULL;
00198
00199 if(sites) {
00200 new_list = Curl_llist_alloc((curl_llist_dtor) site_blacklist_llist_dtor);
00201 if(!new_list)
00202 return CURLM_OUT_OF_MEMORY;
00203
00204
00205 while(*sites) {
00206 char *hostname;
00207 char *port;
00208 struct site_blacklist_entry *entry;
00209
00210 hostname = strdup(*sites);
00211 if(!hostname) {
00212 Curl_llist_destroy(new_list, NULL);
00213 return CURLM_OUT_OF_MEMORY;
00214 }
00215
00216 entry = malloc(sizeof(struct site_blacklist_entry));
00217 if(!entry) {
00218 free(hostname);
00219 Curl_llist_destroy(new_list, NULL);
00220 return CURLM_OUT_OF_MEMORY;
00221 }
00222
00223 port = strchr(hostname, ':');
00224 if(port) {
00225 *port = '\0';
00226 port++;
00227 entry->port = (unsigned short)strtol(port, NULL, 10);
00228 }
00229 else {
00230
00231 entry->port = 80;
00232 }
00233
00234 entry->hostname = hostname;
00235
00236 if(!Curl_llist_insert_next(new_list, new_list->tail, entry)) {
00237 site_blacklist_llist_dtor(NULL, entry);
00238 Curl_llist_destroy(new_list, NULL);
00239 return CURLM_OUT_OF_MEMORY;
00240 }
00241
00242 sites++;
00243 }
00244 }
00245
00246
00247 if(old_list) {
00248 Curl_llist_destroy(old_list, NULL);
00249 }
00250
00251
00252 *list_ptr = new_list;
00253
00254 return CURLM_OK;
00255 }
00256
00257 bool Curl_pipeline_server_blacklisted(struct Curl_easy *handle,
00258 char *server_name)
00259 {
00260 if(handle->multi && server_name) {
00261 struct curl_llist *blacklist =
00262 Curl_multi_pipelining_server_bl(handle->multi);
00263
00264 if(blacklist) {
00265 struct curl_llist_element *curr;
00266
00267 curr = blacklist->head;
00268 while(curr) {
00269 char *bl_server_name;
00270
00271 bl_server_name = curr->ptr;
00272 if(strncasecompare(bl_server_name, server_name,
00273 strlen(bl_server_name))) {
00274 infof(handle, "Server %s is blacklisted\n", server_name);
00275 return TRUE;
00276 }
00277 curr = curr->next;
00278 }
00279 }
00280
00281 DEBUGF(infof(handle, "Server %s is not blacklisted\n", server_name));
00282 }
00283 return FALSE;
00284 }
00285
00286 CURLMcode Curl_pipeline_set_server_blacklist(char **servers,
00287 struct curl_llist **list_ptr)
00288 {
00289 struct curl_llist *old_list = *list_ptr;
00290 struct curl_llist *new_list = NULL;
00291
00292 if(servers) {
00293 new_list = Curl_llist_alloc((curl_llist_dtor) server_blacklist_llist_dtor);
00294 if(!new_list)
00295 return CURLM_OUT_OF_MEMORY;
00296
00297
00298 while(*servers) {
00299 char *server_name;
00300
00301 server_name = strdup(*servers);
00302 if(!server_name) {
00303 Curl_llist_destroy(new_list, NULL);
00304 return CURLM_OUT_OF_MEMORY;
00305 }
00306
00307 if(!Curl_llist_insert_next(new_list, new_list->tail, server_name)) {
00308 Curl_llist_destroy(new_list, NULL);
00309 Curl_safefree(server_name);
00310 return CURLM_OUT_OF_MEMORY;
00311 }
00312
00313 servers++;
00314 }
00315 }
00316
00317
00318 if(old_list) {
00319 Curl_llist_destroy(old_list, NULL);
00320 }
00321
00322
00323 *list_ptr = new_list;
00324
00325 return CURLM_OK;
00326 }
00327
00328 static bool pipe_head(struct Curl_easy *data,
00329 struct curl_llist *pipeline)
00330 {
00331 if(pipeline) {
00332 struct curl_llist_element *curr = pipeline->head;
00333 if(curr)
00334 return (curr->ptr == data) ? TRUE : FALSE;
00335 }
00336 return FALSE;
00337 }
00338
00339
00340 bool Curl_recvpipe_head(struct Curl_easy *data,
00341 struct connectdata *conn)
00342 {
00343 return pipe_head(data, conn->recv_pipe);
00344 }
00345
00346
00347 bool Curl_sendpipe_head(struct Curl_easy *data,
00348 struct connectdata *conn)
00349 {
00350 return pipe_head(data, conn->send_pipe);
00351 }
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361 bool Curl_pipeline_checkget_write(struct Curl_easy *data,
00362 struct connectdata *conn)
00363 {
00364 if(conn->bits.multiplex)
00365
00366 return TRUE;
00367
00368 if(!conn->writechannel_inuse && Curl_sendpipe_head(data, conn)) {
00369
00370 conn->writechannel_inuse = TRUE;
00371 return TRUE;
00372 }
00373 return FALSE;
00374 }
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384 bool Curl_pipeline_checkget_read(struct Curl_easy *data,
00385 struct connectdata *conn)
00386 {
00387 if(conn->bits.multiplex)
00388
00389 return TRUE;
00390
00391 if(!conn->readchannel_inuse && Curl_recvpipe_head(data, conn)) {
00392
00393 conn->readchannel_inuse = TRUE;
00394 return TRUE;
00395 }
00396 return FALSE;
00397 }
00398
00399
00400
00401
00402 void Curl_pipeline_leave_write(struct connectdata *conn)
00403 {
00404 conn->writechannel_inuse = FALSE;
00405 }
00406
00407
00408
00409
00410 void Curl_pipeline_leave_read(struct connectdata *conn)
00411 {
00412 conn->readchannel_inuse = FALSE;
00413 }
00414
00415
00416 #if 0
00417 void print_pipeline(struct connectdata *conn)
00418 {
00419 struct curl_llist_element *curr;
00420 struct connectbundle *cb_ptr;
00421 struct Curl_easy *data = conn->data;
00422
00423 cb_ptr = conn->bundle;
00424
00425 if(cb_ptr) {
00426 curr = cb_ptr->conn_list->head;
00427 while(curr) {
00428 conn = curr->ptr;
00429 infof(data, "- Conn %ld (%p) send_pipe: %zu, recv_pipe: %zu\n",
00430 conn->connection_id,
00431 (void *)conn,
00432 conn->send_pipe->size,
00433 conn->recv_pipe->size);
00434 curr = curr->next;
00435 }
00436 }
00437 }
00438
00439 #endif