struct curltime now;
DEBUGASSERT(data->conn);
+
+ if(!CONN_SOCK_IDX_VALID(sockindex))
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+
/* Get the first connected filter that is not shut down already. */
cf = data->conn->cfilter[sockindex];
while(cf && (!cf->connected || cf->shutdown))
DEBUGASSERT(data);
DEBUGASSERT(data->conn);
+ if(!CONN_SOCK_IDX_VALID(sockindex))
+ return CURLE_BAD_FUNCTION_ARGUMENT;
cf = data->conn->cfilter[sockindex];
if(!cf) {
bool Curl_conn_is_setup(struct connectdata *conn, int sockindex)
{
+ if(!CONN_SOCK_IDX_VALID(sockindex))
+ return FALSE;
return (conn->cfilter[sockindex] != NULL);
}
{
struct Curl_cfilter *cf;
+ if(!CONN_SOCK_IDX_VALID(sockindex))
+ return FALSE;
cf = conn->cfilter[sockindex];
return cf && cf->connected;
}
{
struct Curl_cfilter *cf;
+ if(!CONN_SOCK_IDX_VALID(sockindex))
+ return FALSE;
cf = data->conn->cfilter[sockindex];
while(cf) {
if(cf->connected)
bool Curl_conn_is_ssl(struct connectdata *conn, int sockindex)
{
+ if(!CONN_SOCK_IDX_VALID(sockindex))
+ return FALSE;
return conn ? cf_is_ssl(conn->cfilter[sockindex]) : FALSE;
}
struct connectdata *conn, int sockindex,
struct curl_tlssessioninfo *info)
{
+ if(!CONN_SOCK_IDX_VALID(sockindex))
+ return FALSE;
if(Curl_conn_is_ssl(conn, sockindex)) {
struct Curl_cfilter *cf = conn->cfilter[sockindex];
CURLcode result = cf ? cf->cft->query(cf, data, CF_QUERY_SSL_INFO,
struct connectdata *conn, int sockindex,
bool *is_ipv6, struct ip_quadruple *ipquad)
{
- struct Curl_cfilter *cf = conn ? conn->cfilter[sockindex] : NULL;
+ struct Curl_cfilter *cf;
+ if(!CONN_SOCK_IDX_VALID(sockindex))
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ cf = conn ? conn->cfilter[sockindex] : NULL;
return Curl_conn_cf_get_ip_info(cf, data, is_ipv6, ipquad);
}
bool Curl_conn_is_multiplex(struct connectdata *conn, int sockindex)
{
- struct Curl_cfilter *cf = conn ? conn->cfilter[sockindex] : NULL;
+ struct Curl_cfilter *cf;
+
+ if(!CONN_SOCK_IDX_VALID(sockindex))
+ return FALSE;
+ cf = conn ? conn->cfilter[sockindex] : NULL;
for(; cf; cf = cf->next) {
if(cf->cft->flags & CF_TYPE_MULTIPLEX)
(void)data;
DEBUGASSERT(data);
DEBUGASSERT(data->conn);
+ if(!CONN_SOCK_IDX_VALID(sockindex))
+ return FALSE;
cf = data->conn->cfilter[sockindex];
while(cf && !cf->connected) {
bool Curl_conn_needs_flush(struct Curl_easy *data, int sockindex)
{
+ if(!CONN_SOCK_IDX_VALID(sockindex))
+ return FALSE;
return Curl_conn_cf_needs_flush(data->conn->cfilter[sockindex], data);
}
{
struct Curl_cfilter *cf, *cf_proxy = NULL;
- DEBUGASSERT(data->conn);
- cf = data->conn->cfilter[sockindex];
+ if(!data->conn) {
+ DEBUGASSERT(0);
+ *phost = "";
+ *pport = -1;
+ return;
+ }
+
+ cf = CONN_SOCK_IDX_VALID(sockindex) ? data->conn->cfilter[sockindex] : NULL;
/* Find the "lowest" tunneling proxy filter that has not connected yet. */
while(cf && !cf->connected) {
if((cf->cft->flags & (CF_TYPE_IP_CONNECT|CF_TYPE_PROXY)) ==
{
struct Curl_cfilter *cf;
- cf = data->conn ? data->conn->cfilter[sockindex] : NULL;
+ cf = (data->conn && CONN_SOCK_IDX_VALID(sockindex)) ?
+ data->conn->cfilter[sockindex] : NULL;
/* if the top filter has not connected, ask it (and its sub-filters)
* for the socket. Otherwise conn->sock[sockindex] should have it.
*/
const struct Curl_sockaddr_ex *
Curl_conn_get_remote_addr(struct Curl_easy *data, int sockindex)
{
- struct Curl_cfilter *cf = data->conn ? data->conn->cfilter[sockindex] : NULL;
+ struct Curl_cfilter *cf =
+ (data->conn && CONN_SOCK_IDX_VALID(sockindex)) ?
+ data->conn->cfilter[sockindex] : NULL;
return cf ? cf_get_remote_addr(cf, data) : NULL;
}
void Curl_conn_forget_socket(struct Curl_easy *data, int sockindex)
{
- if(data->conn) {
+ if(data->conn && CONN_SOCK_IDX_VALID(sockindex)) {
struct Curl_cfilter *cf = data->conn->cfilter[sockindex];
if(cf)
(void)Curl_conn_cf_cntrl(cf, data, TRUE,
CURLcode Curl_conn_flush(struct Curl_easy *data, int sockindex)
{
+ if(!CONN_SOCK_IDX_VALID(sockindex))
+ return CURLE_BAD_FUNCTION_ARGUMENT;
return Curl_conn_cf_cntrl(data->conn->cfilter[sockindex], data, FALSE,
CF_CTRL_FLUSH, 0, NULL);
}
struct connectdata *conn,
int sockindex)
{
- struct Curl_cfilter *cf = conn->cfilter[sockindex];
+ struct Curl_cfilter *cf;
+
+ if(!CONN_SOCK_IDX_VALID(sockindex))
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ cf = conn->cfilter[sockindex];
return cf ? cf->cft->keep_alive(cf, data) : CURLE_OK;
}
struct connectdata *conn,
int sockindex)
{
+ struct Curl_cfilter *cf;
CURLcode result;
int n = -1;
- struct Curl_cfilter *cf = conn->cfilter[sockindex];
+ if(!CONN_SOCK_IDX_VALID(sockindex))
+ return 0;
+
+ cf = conn->cfilter[sockindex];
result = cf ? cf->cft->query(cf, data, CF_QUERY_MAX_CONCURRENT,
&n, NULL) : CURLE_UNKNOWN_OPTION;
/* If no filter answered the query, the default is a non-multiplexed
struct connectdata *conn,
int sockindex)
{
+ struct Curl_cfilter *cf;
CURLcode result;
int n = 0;
- struct Curl_cfilter *cf = conn->cfilter[sockindex];
+ if(!CONN_SOCK_IDX_VALID(sockindex))
+ return 0;
+
+ cf = conn->cfilter[sockindex];
result = cf ? cf->cft->query(cf, data, CF_QUERY_STREAM_ERROR,
&n, NULL) : CURLE_UNKNOWN_OPTION;
return (result || n < 0) ? 0 : n;
{
DEBUGASSERT(data);
DEBUGASSERT(data->conn);
+ if(!CONN_SOCK_IDX_VALID(sockindex))
+ return CURLE_BAD_FUNCTION_ARGUMENT;
if(data && data->conn && data->conn->recv[sockindex])
return data->conn->recv[sockindex](data, sockindex, buf, blen, pnread);
*pnread = 0;
DEBUGASSERT(data);
DEBUGASSERT(data->conn);
- DEBUGASSERT(sockindex >= 0 && sockindex < 2);
+ DEBUGASSERT(CONN_SOCK_IDX_VALID(sockindex));
+ if(!CONN_SOCK_IDX_VALID(sockindex))
+ return CURLE_BAD_FUNCTION_ARGUMENT;
#ifdef DEBUGBUILD
if(write_len) {
/* Allow debug builds to override this logic to force short sends
if(result)
goto fail;
info_version = "HTTP/2";
- /* There is no ALPN here, but the connection is now definitely h2 */
- conn->httpversion_seen = 20;
}
else
info_version = "HTTP/1.x";
static CURLcode mstate_do_pollset(struct Curl_easy *data,
struct easy_pollset *ps)
{
- struct connectdata *conn = data->conn;
if(data->conn) {
if(data->conn->handler->doing_pollset)
return data->conn->handler->doing_pollset(data, ps);
- else if(conn->sockfd != CURL_SOCKET_BAD) {
+ else if(CONN_SOCK_IDX_VALID(data->conn->send_idx)) {
/* Default is that we want to send something to the server */
- return Curl_pollset_add_out(data, ps, conn->sockfd);
+ return Curl_pollset_add_out(
+ data, ps, data->conn->sock[data->conn->send_idx]);
}
}
return CURLE_OK;
if(data->conn) {
if(data->conn->handler->domore_pollset)
return data->conn->handler->domore_pollset(data, ps);
- else if(data->conn->sockfd != CURL_SOCKET_BAD) {
+ else if(CONN_SOCK_IDX_VALID(data->conn->send_idx)) {
/* Default is that we want to send something to the server */
- return Curl_pollset_add_out(data, ps, data->conn->sockfd);
+ return Curl_pollset_add_out(
+ data, ps, data->conn->sock[data->conn->send_idx]);
}
}
return CURLE_OK;
else {
/* Default is to obey the data->req.keepon flags for send/recv */
CURLcode result = CURLE_OK;
- if(CURL_WANT_RECV(data)) {
- DEBUGASSERT(data->conn->sockfd != CURL_SOCKET_BAD);
- result = Curl_pollset_add_in(data, ps, data->conn->sockfd);
+ if(CURL_WANT_RECV(data) && CONN_SOCK_IDX_VALID(data->conn->recv_idx)) {
+ result = Curl_pollset_add_in(
+ data, ps, data->conn->sock[data->conn->recv_idx]);
}
- if(!result && Curl_req_want_send(data)) {
- DEBUGASSERT(data->conn->writesockfd != CURL_SOCKET_BAD);
- result = Curl_pollset_add_out(data, ps, data->conn->writesockfd);
+ if(!result && Curl_req_want_send(data) &&
+ CONN_SOCK_IDX_VALID(data->conn->send_idx)) {
+ result = Curl_pollset_add_out(
+ data, ps, data->conn->sock[data->conn->send_idx]);
}
return result;
}
/* Only perform the transfer if there is a good socket to work with.
Having both BAD is a signal to skip immediately to DONE */
- if((data->conn->sockfd != CURL_SOCKET_BAD) ||
- (data->conn->writesockfd != CURL_SOCKET_BAD))
+ if(CONN_SOCK_IDX_VALID(data->conn->recv_idx) ||
+ CONN_SOCK_IDX_VALID(data->conn->send_idx))
multistate(data, MSTATE_PERFORMING);
else {
#ifndef CURL_DISABLE_FTP
static CURLcode xfer_recv_shutdown(struct Curl_easy *data, bool *done)
{
- int sockindex;
-
if(!data || !data->conn)
return CURLE_FAILED_INIT;
- if(data->conn->sockfd == CURL_SOCKET_BAD)
- return CURLE_FAILED_INIT;
- sockindex = (data->conn->sockfd == data->conn->sock[SECONDARYSOCKET]);
- return Curl_conn_shutdown(data, sockindex, done);
+ return Curl_conn_shutdown(data, data->conn->recv_idx, done);
}
static bool xfer_recv_shutdown_started(struct Curl_easy *data)
{
- int sockindex;
-
if(!data || !data->conn)
return FALSE;
- if(data->conn->sockfd == CURL_SOCKET_BAD)
- return FALSE;
- sockindex = (data->conn->sockfd == data->conn->sock[SECONDARYSOCKET]);
- return Curl_shutdown_started(data, sockindex);
+ return Curl_shutdown_started(data, data->conn->recv_idx);
}
CURLcode Curl_xfer_send_shutdown(struct Curl_easy *data, bool *done)
{
- int sockindex;
-
if(!data || !data->conn)
return CURLE_FAILED_INIT;
- if(data->conn->writesockfd == CURL_SOCKET_BAD)
- return CURLE_FAILED_INIT;
- sockindex = (data->conn->writesockfd == data->conn->sock[SECONDARYSOCKET]);
- return Curl_conn_shutdown(data, sockindex, done);
+ return Curl_conn_shutdown(data, data->conn->send_idx, done);
}
/**
if(Curl_conn_is_multiplex(conn, FIRSTSOCKET) || want_send) {
/* when multiplexing, the read/write sockets need to be the same! */
- conn->sockfd = sockindex == -1 ?
- ((writesockindex == -1 ? CURL_SOCKET_BAD : conn->sock[writesockindex])) :
- conn->sock[sockindex];
- conn->writesockfd = conn->sockfd;
if(want_send)
/* special and HTTP-specific */
writesockindex = FIRSTSOCKET;
+ conn->recv_idx = sockindex;
+ conn->send_idx = writesockindex;
}
else {
- conn->sockfd = sockindex == -1 ?
- CURL_SOCKET_BAD : conn->sock[sockindex];
- conn->writesockfd = writesockindex == -1 ?
- CURL_SOCKET_BAD : conn->sock[writesockindex];
+ conn->recv_idx = sockindex;
+ conn->send_idx = writesockindex;
}
k->getheader = getheader;
k->keepon |= KEEP_SEND;
} /* if(k->getheader || !data->req.no_body) */
+ CURL_TRC_M(data, "transfer setup: recv_idx=%d, send_idx=%d",
+ conn->recv_idx, conn->send_idx);
}
void Curl_xfer_setup_nop(struct Curl_easy *data)
bool Curl_xfer_needs_flush(struct Curl_easy *data)
{
- int sockindex;
- sockindex = ((data->conn->writesockfd != CURL_SOCKET_BAD) &&
- (data->conn->writesockfd == data->conn->sock[SECONDARYSOCKET]));
- return Curl_conn_needs_flush(data, sockindex);
+ return Curl_conn_needs_flush(data, data->conn->send_idx);
}
CURLcode Curl_xfer_flush(struct Curl_easy *data)
{
- int sockindex;
- sockindex = ((data->conn->writesockfd != CURL_SOCKET_BAD) &&
- (data->conn->writesockfd == data->conn->sock[SECONDARYSOCKET]));
- return Curl_conn_flush(data, sockindex);
+ return Curl_conn_flush(data, data->conn->send_idx);
}
CURLcode Curl_xfer_send(struct Curl_easy *data,
size_t *pnwritten)
{
CURLcode result;
- int sockindex;
DEBUGASSERT(data);
DEBUGASSERT(data->conn);
- sockindex = ((data->conn->writesockfd != CURL_SOCKET_BAD) &&
- (data->conn->writesockfd == data->conn->sock[SECONDARYSOCKET]));
- result = Curl_conn_send(data, sockindex, buf, blen, eos, pnwritten);
+ result = Curl_conn_send(data, data->conn->send_idx,
+ buf, blen, eos, pnwritten);
if(result == CURLE_AGAIN) {
result = CURLE_OK;
*pnwritten = 0;
char *buf, size_t blen,
size_t *pnrcvd)
{
- int sockindex;
-
DEBUGASSERT(data);
DEBUGASSERT(data->conn);
DEBUGASSERT(data->set.buffer_size > 0);
- sockindex = ((data->conn->sockfd != CURL_SOCKET_BAD) &&
- (data->conn->sockfd == data->conn->sock[SECONDARYSOCKET]));
if((size_t)data->set.buffer_size < blen)
blen = (size_t)data->set.buffer_size;
- return Curl_conn_recv(data, sockindex, buf, blen, pnrcvd);
+ return Curl_conn_recv(data, data->conn->recv_idx, buf, blen, pnrcvd);
}
CURLcode Curl_xfer_send_close(struct Curl_easy *data)
conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */
conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */
- conn->sockfd = CURL_SOCKET_BAD;
- conn->writesockfd = CURL_SOCKET_BAD;
+ conn->recv_idx = 0; /* default for receiving transfer data */
+ conn->send_idx = 0; /* default for sending transfer data */
conn->connection_id = -1; /* no ID */
conn->remote_port = -1; /* unknown at this point */
char *oauth_bearer; /* OAUTH2 bearer, allocated */
struct curltime created; /* creation time */
struct curltime lastused; /* when returned to the connection poolas idle */
- curl_socket_t sock[2]; /* two sockets, the second is used for the data
- transfer when doing FTP */
+
+ /* A connection can have one or two sockets and connection filters.
+ * The protocol using the 2nd one is FTP for CONTROL+DATA sockets */
+ curl_socket_t sock[2];
+ struct Curl_cfilter *cfilter[2]; /* connection filters */
Curl_recv *recv[2];
Curl_send *send[2];
- struct Curl_cfilter *cfilter[2]; /* connection filters */
+ int recv_idx; /* on which socket index to receive, default 0 */
+ int send_idx; /* on which socket index to send, default 0 */
+
+#define CONN_SOCK_IDX_VALID(i) (((i) >= 0) && ((i) < 2))
+
struct {
struct curltime start[2]; /* when filter shutdown started */
timediff_t timeout_ms; /* 0 means no timeout */
/**** curl_get() phase fields */
- curl_socket_t sockfd; /* socket to read from or CURL_SOCKET_BAD */
- curl_socket_t writesockfd; /* socket to write to, it may be the same we read
- from. CURL_SOCKET_BAD disables */
-
#ifdef HAVE_GSSAPI
BIT(sec_complete); /* if Kerberos is enabled for this connection */
unsigned char command_prot; /* enum protection_level */
/* At this point we have an authenticated ssh session. */
infof(data, "Authentication complete");
Curl_pgrsTime(data, TIMER_APPCONNECT); /* SSH is connected */
- data->conn->sockfd = data->conn->sock[FIRSTSOCKET];
- data->conn->writesockfd = CURL_SOCKET_BAD;
+ data->conn->recv_idx = FIRSTSOCKET;
+ data->conn->send_idx = -1;
if(data->conn->handler->protocol == CURLPROTO_SFTP) {
myssh_to(data, sshc, SSH_SFTP_INIT);
Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE);
/* not set by Curl_xfer_setup to preserve keepon bits */
- data->conn->sockfd = data->conn->writesockfd;
+ data->conn->recv_idx = FIRSTSOCKET;
/* store this original bitmask setup to use later on if we cannot
figure out a "real" bitmask */
Curl_xfer_setup1(data, CURL_XFER_RECV, data->req.size, FALSE);
/* not set by Curl_xfer_setup to preserve keepon bits */
- data->conn->writesockfd = data->conn->sockfd;
+ data->conn->send_idx = 0;
sshc->sftp_recv_state = 0;
myssh_to(data, sshc, SSH_STOP);
Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE);
/* not set by Curl_xfer_setup to preserve keepon bits */
- conn->sockfd = conn->writesockfd;
+ data->conn->recv_idx = FIRSTSOCKET;
/* store this original bitmask setup to use later on if we cannot
figure out a "real" bitmask */
Curl_xfer_setup1(data, CURL_XFER_RECV, bytecount, FALSE);
/* not set by Curl_xfer_setup to preserve keepon bits */
- conn->writesockfd = conn->sockfd;
+ conn->send_idx = 0;
myssh_to(data, sshc, SSH_STOP);
break;
Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE);
/* not set by Curl_xfer_setup to preserve keepon bits */
- data->conn->sockfd = data->conn->writesockfd;
+ data->conn->recv_idx = FIRSTSOCKET;
/* store this original bitmask setup to use later on if we cannot
figure out a "real" bitmask */
Curl_xfer_setup1(data, CURL_XFER_RECV, data->req.size, FALSE);
/* not set by Curl_xfer_setup to preserve keepon bits */
- data->conn->writesockfd = data->conn->sockfd;
+ data->conn->send_idx = 0;
myssh_state(data, sshc, SSH_STOP);
Curl_pgrsTime(data, TIMER_APPCONNECT); /* SSH is connected */
- conn->sockfd = conn->sock[FIRSTSOCKET];
- conn->writesockfd = CURL_SOCKET_BAD;
+ data->conn->recv_idx = FIRSTSOCKET;
+ conn->send_idx = -1;
if(conn->handler->protocol == CURLPROTO_SFTP) {
myssh_state(data, sshc, SSH_SFTP_INIT);
Curl_xfer_setup1(data, CURL_XFER_RECV, bytecount, FALSE);
/* not set by Curl_xfer_setup to preserve keepon bits */
- data->conn->writesockfd = data->conn->sockfd;
+ data->conn->send_idx = 0;
myssh_state(data, sshc, SSH_STOP);
return CURLE_OK;
Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE);
/* not set by Curl_xfer_setup to preserve keepon bits */
- data->conn->sockfd = data->conn->writesockfd;
+ data->conn->recv_idx = FIRSTSOCKET;
/* store this original bitmask setup to use later on if we cannot
figure out a "real" bitmask */
Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE);
/* not set by Curl_xfer_setup to preserve keepon bits */
- conn->sockfd = conn->writesockfd;
+ data->conn->recv_idx = FIRSTSOCKET;
if(result) {
wssh_state(data, sshc, SSH_SFTP_CLOSE);
Curl_xfer_setup1(data, CURL_XFER_RECV, data->req.size, FALSE);
/* not set by Curl_xfer_setup to preserve keepon bits */
- conn->writesockfd = conn->sockfd;
+ conn->send_idx = 0;
if(result) {
/* this should never occur; the close state should be entered