Skip to content

Commit

Permalink
CURLMOPT_PIPELINE: bit 1 is for multiplexing
Browse files Browse the repository at this point in the history
  • Loading branch information
bagder committed May 18, 2015
1 parent 2ce2f03 commit 02ec1ce
Show file tree
Hide file tree
Showing 8 changed files with 48 additions and 36 deletions.
27 changes: 19 additions & 8 deletions docs/libcurl/opts/CURLMOPT_PIPELINING.3
Expand Up @@ -5,7 +5,7 @@
.\" * | (__| |_| | _ <| |___
.\" * \___|\___/|_| \_\_____|
.\" *
.\" * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
.\" * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
.\" *
.\" * This software is licensed as described in the file COPYING, which
.\" * you should have received as part of this distribution. The terms
Expand All @@ -26,25 +26,36 @@ CURLMOPT_PIPELINING \- enable/disable HTTP pipelining
.SH SYNOPSIS
#include <curl/curl.h>

CURLMcode curl_multi_setopt(CURLM *handle, CURLMOPT_PIPELINING, bool onoff);
CURLMcode curl_multi_setopt(CURLM *handle, CURLMOPT_PIPELINING, long bits);
.SH DESCRIPTION
Set the \fBonoff\fP parameter to 1 to make libcurl use HTTP pipelining for
HTTP transfers done using this multi handle, as far as possible. This means
that if you add a second request that can use an already existing connection,
the second request will be \&"piped" on the same connection rather than being
executed in parallel.
Set the \fBbits\fP parameter to 1 to make libcurl use HTTP pipelining for
HTTP/1.1 transfers done using this multi handle, as far as possible. This
means that if you add a second request that can use an already existing
connection, the second request will be \&"piped" on the same connection rather
than being executed in parallel.

When using pipelining, there are also several other related options that are
interesting to tweak and adjust to alter how libcurl spreads out requests on
different connections or not etc.

Starting in 7.43.0, the \fBbits\fP parameter's bit 1 also has a meaning and
libcurl is now offering symbol names for the bits:
.IP CURLPIPE_NOTHING (0)
Default, which means doing no attempts at pipelining or multiplexing.
.IP CURLPIPE_HTTP1 (1)
If this bit is set, libcurl will try to pipeline HTTP/1.1 requests on
connections that are already established and in use to hosts.
.IP CURLPIPE_MULTIPLEX (2)
If this bit is set, libcurl will try to multiplex the new transfer over an
existing connection if possible. This requires HTTP/2.
.SH DEFAULT
0 (off)
.SH PROTOCOLS
HTTP(S)
.SH EXAMPLE
TODO
.SH AVAILABILITY
Added in 7.16.0
Added in 7.16.0. Multiplex support bit added in 7.43.0.
.SH RETURN VALUE
Returns CURLM_OK if the option is supported, and CURLM_UNKNOWN_OPTION if not.
.SH "SEE ALSO"
Expand Down
7 changes: 6 additions & 1 deletion include/curl/multi.h
Expand Up @@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
Expand Down Expand Up @@ -74,6 +74,11 @@ typedef enum {
curl_multi_perform() and CURLM_CALL_MULTI_PERFORM */
#define CURLM_CALL_MULTI_SOCKET CURLM_CALL_MULTI_PERFORM

/* bitmask bits for CURLMOPT_PIPELINING */
#define CURLPIPE_NOTHING 0L
#define CURLPIPE_HTTP1 1L
#define CURLPIPE_MULTIPLEX 2L

typedef enum {
CURLMSG_NONE, /* first, not used */
CURLMSG_DONE, /* This easy handle has completed. 'result' contains
Expand Down
15 changes: 8 additions & 7 deletions lib/multi.c
Expand Up @@ -613,9 +613,10 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
return CURLM_OK;
}

bool Curl_multi_pipeline_enabled(const struct Curl_multi *multi)
/* Return TRUE if the application asked for a certain set of pipelining */
bool Curl_pipeline_wanted(const struct Curl_multi *multi, int bits)
{
return (multi && multi->pipelining_enabled) ? TRUE : FALSE;
return (multi && (multi->pipelining & bits)) ? TRUE : FALSE;
}

void Curl_multi_handlePipeBreak(struct SessionHandle *data)
Expand Down Expand Up @@ -1082,7 +1083,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
rc = CURLM_CALL_MULTI_PERFORM;

if(protocol_connect)
multistate(data, multi->pipelining_enabled?
multistate(data, Curl_pipeline_wanted(multi, CURLPIPE_HTTP1)?
CURLM_STATE_WAITDO:CURLM_STATE_DO);
else {
#ifndef CURL_DISABLE_HTTP
Expand Down Expand Up @@ -1139,7 +1140,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* call again please so that we get the next socket setup */
rc = CURLM_CALL_MULTI_PERFORM;
if(protocol_connect)
multistate(data, multi->pipelining_enabled?
multistate(data, Curl_pipeline_wanted(multi, CURLPIPE_HTTP1)?
CURLM_STATE_WAITDO:CURLM_STATE_DO);
else {
#ifndef CURL_DISABLE_HTTP
Expand Down Expand Up @@ -1203,7 +1204,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
multistate(data, CURLM_STATE_PROTOCONNECT);
else if(!result) {
/* protocol connect has completed, go WAITDO or DO */
multistate(data, multi->pipelining_enabled?
multistate(data, Curl_pipeline_wanted(multi, CURLPIPE_HTTP1)?
CURLM_STATE_WAITDO:CURLM_STATE_DO);
rc = CURLM_CALL_MULTI_PERFORM;
}
Expand All @@ -1220,7 +1221,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
result = Curl_protocol_connecting(data->easy_conn, &protocol_connect);
if(!result && protocol_connect) {
/* after the connect has completed, go WAITDO or DO */
multistate(data, multi->pipelining_enabled?
multistate(data, Curl_pipeline_wanted(multi, CURLPIPE_HTTP1)?
CURLM_STATE_WAITDO:CURLM_STATE_DO);
rc = CURLM_CALL_MULTI_PERFORM;
}
Expand Down Expand Up @@ -2340,7 +2341,7 @@ CURLMcode curl_multi_setopt(CURLM *multi_handle,
multi->socket_userp = va_arg(param, void *);
break;
case CURLMOPT_PIPELINING:
multi->pipelining_enabled = (0 != va_arg(param, long)) ? TRUE : FALSE;
multi->pipelining = va_arg(param, long);
break;
case CURLMOPT_TIMERFUNCTION:
multi->timer_cb = va_arg(param, curl_multi_timer_callback);
Expand Down
6 changes: 4 additions & 2 deletions lib/multihandle.h
Expand Up @@ -62,6 +62,8 @@ typedef enum {
#define GETSOCK_READABLE (0x00ff)
#define GETSOCK_WRITABLE (0xff00)

#define CURLPIPE_ANY (CURLPIPE_HTTP1 | CURLPIPE_MULTIPLEX)

/* This is the struct known as CURLM on the outside */
struct Curl_multi {
/* First a simple identifier to easier detect if a user mix up
Expand Down Expand Up @@ -97,8 +99,8 @@ struct Curl_multi {
same actual socket) */
struct curl_hash sockhash;

/* Whether pipelining is enabled for this multi handle */
bool pipelining_enabled;
/* pipelining wanted bits (CURLPIPE*) */
long pipelining;

/* Shared connection cache (bundles)*/
struct conncache conn_cache;
Expand Down
5 changes: 2 additions & 3 deletions lib/multiif.h
Expand Up @@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
Expand All @@ -27,8 +27,7 @@
*/
void Curl_expire(struct SessionHandle *data, long milli);
void Curl_expire_latest(struct SessionHandle *data, long milli);

bool Curl_multi_pipeline_enabled(const struct Curl_multi* multi);
bool Curl_pipeline_wanted(const struct Curl_multi* multi, int bits);
void Curl_multi_handlePipeBreak(struct SessionHandle *data);

/* Internal version of curl_multi_init() accepts size parameters for the
Expand Down
3 changes: 1 addition & 2 deletions lib/sendf.c
Expand Up @@ -551,8 +551,7 @@ CURLcode Curl_read(struct connectdata *conn, /* connection data */
ssize_t nread = 0;
size_t bytesfromsocket = 0;
char *buffertofill = NULL;
bool pipelining = Curl_multi_pipeline_enabled(conn->data->multi) &&
!conn->bits.multiplex;
bool pipelining = Curl_pipeline_wanted(conn->data->multi, CURLPIPE_HTTP1);

/* Set 'num' to 0 or 1, depending on which socket that has been sent here.
If it is the second socket, we set num to 1. Otherwise to 0. This lets
Expand Down
6 changes: 3 additions & 3 deletions lib/transfer.c
Expand Up @@ -494,7 +494,7 @@ static CURLcode readwrite_data(struct SessionHandle *data,
/* We've stopped dealing with input, get out of the do-while loop */

if(nread > 0) {
if(Curl_multi_pipeline_enabled(conn->data->multi)) {
if(Curl_pipeline_wanted(conn->data->multi, CURLPIPE_HTTP1)) {
infof(data,
"Rewinding stream by : %zd"
" bytes on url %s (zero-length body)\n",
Expand Down Expand Up @@ -639,7 +639,7 @@ static CURLcode readwrite_data(struct SessionHandle *data,
if(dataleft != 0) {
infof(conn->data, "Leftovers after chunking: %zu bytes\n",
dataleft);
if(Curl_multi_pipeline_enabled(conn->data->multi)) {
if(Curl_pipeline_wanted(conn->data->multi, CURLPIPE_HTTP1)) {
/* only attempt the rewind if we truly are pipelining */
infof(conn->data, "Rewinding %zu bytes\n",dataleft);
read_rewind(conn, dataleft);
Expand All @@ -662,7 +662,7 @@ static CURLcode readwrite_data(struct SessionHandle *data,

excess = (size_t)(k->bytecount + nread - k->maxdownload);
if(excess > 0 && !k->ignorebody) {
if(Curl_multi_pipeline_enabled(conn->data->multi)) {
if(Curl_pipeline_wanted(conn->data->multi, CURLPIPE_HTTP1)) {
/* The 'excess' amount below can't be more than BUFSIZE which
always will fit in a size_t */
infof(data,
Expand Down
15 changes: 5 additions & 10 deletions lib/url.c
Expand Up @@ -2782,7 +2782,7 @@ CURLcode Curl_disconnect(struct connectdata *conn, bool dead_connection)
Curl_ssl_close(conn, FIRSTSOCKET);

/* Indicate to all handles on the pipe that we're dead */
if(Curl_multi_pipeline_enabled(data->multi)) {
if(Curl_pipeline_wanted(data->multi, CURLPIPE_ANY)) {
signalPipeClose(conn->send_pipe, TRUE);
signalPipeClose(conn->recv_pipe, TRUE);
}
Expand Down Expand Up @@ -2815,7 +2815,7 @@ static bool IsPipeliningPossible(const struct SessionHandle *handle,
{
/* If a HTTP protocol and pipelining is enabled */
if((conn->handler->protocol & PROTO_FAMILY_HTTP) &&
Curl_multi_pipeline_enabled(handle->multi)) {
Curl_pipeline_wanted(handle->multi, CURLPIPE_ANY)) {

if((handle->set.httpversion != CURL_HTTP_VERSION_1_0) &&
(handle->set.httpreq == HTTPREQ_GET ||
Expand All @@ -2830,11 +2830,6 @@ static bool IsPipeliningPossible(const struct SessionHandle *handle,
return FALSE;
}

bool Curl_isPipeliningEnabled(const struct SessionHandle *handle)
{
return Curl_multi_pipeline_enabled(handle->multi);
}

int Curl_removeHandleFromPipeline(struct SessionHandle *handle,
struct curl_llist *pipeline)
{
Expand Down Expand Up @@ -3786,9 +3781,9 @@ static struct connectdata *allocate_conn(struct SessionHandle *data)
conn->response_header = NULL;
#endif

if(Curl_multi_pipeline_enabled(data->multi) &&
!conn->master_buffer) {
/* Allocate master_buffer to be used for pipelining */
if(Curl_pipeline_wanted(data->multi, CURLPIPE_HTTP1) &&
!conn->master_buffer) {
/* Allocate master_buffer to be used for HTTP/1 pipelining */
conn->master_buffer = calloc(BUFSIZE, sizeof (char));
if(!conn->master_buffer)
goto error;
Expand Down

0 comments on commit 02ec1ce

Please sign in to comment.