cf-socket: improvements in socket I/O handling

- Curl_write_plain/Curl_read_plain have been eliminated. Last code use
  now uses Curl_conn_send/recv so that requests use conn->send/revc
  callbacks which defaults to cfilters use.
- Curl_recv_plain/Curl_send_plain have been internalized in cf-socket.c.
- USE_RECV_BEFORE_SEND_WORKAROUND (active on Windows) has been moved
  into cf-socket.c. The pre_recv buffer is held at the socket filter
  context.  `postponed_data` structures have been removed from
  `connectdata`.
- the hanger in HTTP/2 request handling was a result of read buffering
  on all sends and the multi handling is not prepared for this. The
  following happens:

   - multi preforms on a HTTP/2 easy handle
   - h2 reads and processes data
   - this leads to a send of h2 data
   - which receives and buffers before the send
   - h2 returns
   - multi selects on the socket, but no data arrives (its in the buffer already)
   the workaround now receives data in a loop as long as there is something in
   the buffer. The real fix would be for multi to change, so that `data_pending`
   is evaluated before deciding to wait on the socket.

io_buffer, optional, in cf-socket.c, http/2 sets state.drain if lower
filter have pending data.

This io_buffer is only available/used when the
-DUSE_RECV_BEFORE_SEND_WORKAROUND is active, e.g. on Windows
configurations. It also maintains the original checks on protocol
handler being HTTP and conn->send/recv not being replaced.

The HTTP/2 (nghttp2) cfilter now sets data->state.drain when it finds
out that the "lower" filter chain has still pending data at the end of
its IO operation. This prevents the processing from becoming stalled.

Closes #10280
This commit is contained in:
Stefan Eissing 2023-01-30 16:03:00 +01:00 committed by Daniel Stenberg
parent a3bcfab4b5
commit 5651a36d1a
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
14 changed files with 402 additions and 572 deletions

View File

@ -742,11 +742,29 @@ CURLcode Curl_socket_connect_result(struct Curl_easy *data,
}
}
#ifdef USE_RECV_BEFORE_SEND_WORKAROUND
struct io_buffer {
char *bufr;
size_t allc; /* size of the current allocation */
size_t head; /* bufr index for next read */
size_t tail; /* bufr index for next write */
};
static void io_buffer_reset(struct io_buffer *iob)
{
if(iob->bufr)
free(iob->bufr);
memset(iob, 0, sizeof(*iob));
}
#endif /* USE_RECV_BEFORE_SEND_WORKAROUND */
struct cf_socket_ctx {
int transport;
struct Curl_sockaddr_ex addr; /* address to connect to */
curl_socket_t sock; /* current attempt socket */
#ifdef USE_RECV_BEFORE_SEND_WORKAROUND
struct io_buffer recv_buffer;
#endif
char r_ip[MAX_IPADR_LEN]; /* remote IP as string */
int r_port; /* remote port number */
char l_ip[MAX_IPADR_LEN]; /* local IP as string */
@ -783,6 +801,9 @@ static void cf_socket_close(struct Curl_cfilter *cf, struct Curl_easy *data)
DEBUGF(LOG_CF(data, cf, "cf_socket_close(%d) local", (int)ctx->sock));
sclose(ctx->sock);
}
#ifdef USE_RECV_BEFORE_SEND_WORKAROUND
io_buffer_reset(&ctx->recv_buffer);
#endif
ctx->sock = CURL_SOCKET_BAD;
ctx->active = FALSE;
}
@ -1112,12 +1133,88 @@ static int cf_socket_get_select_socks(struct Curl_cfilter *cf,
return rc;
}
#ifdef USE_RECV_BEFORE_SEND_WORKAROUND
static CURLcode pre_receive_plain(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct cf_socket_ctx *ctx = cf->ctx;
struct io_buffer * const iob = &ctx->recv_buffer;
/* WinSock will destroy unread received data if send() is
failed.
To avoid lossage of received data, recv() must be
performed before every send() if any incoming data is
available. However, skip this, if buffer is already full. */
if((cf->conn->handler->protocol&PROTO_FAMILY_HTTP) != 0 &&
cf->conn->recv[cf->sockindex] == Curl_conn_recv &&
(!iob->bufr || (iob->allc > iob->tail))) {
const int readymask = Curl_socket_check(ctx->sock, CURL_SOCKET_BAD,
CURL_SOCKET_BAD, 0);
if(readymask != -1 && (readymask & CURL_CSELECT_IN) != 0) {
size_t bytestorecv = iob->allc - iob->tail;
ssize_t nread;
/* Have some incoming data */
if(!iob->bufr) {
/* Use buffer double default size for intermediate buffer */
iob->allc = 2 * data->set.buffer_size;
iob->bufr = malloc(iob->allc);
if(!iob->bufr)
return CURLE_OUT_OF_MEMORY;
iob->tail = 0;
iob->head = 0;
bytestorecv = iob->allc;
}
nread = sread(ctx->sock, iob->bufr + iob->tail, bytestorecv);
if(nread > 0)
iob->tail += (size_t)nread;
}
}
return CURLE_OK;
}
static ssize_t get_pre_recved(struct Curl_cfilter *cf, char *buf, size_t len)
{
struct cf_socket_ctx *ctx = cf->ctx;
struct io_buffer * const iob = &ctx->recv_buffer;
size_t copysize;
if(!iob->bufr)
return 0;
DEBUGASSERT(iob->allc > 0);
DEBUGASSERT(iob->tail <= iob->allc);
DEBUGASSERT(iob->head <= iob->tail);
/* Check and process data that already received and storied in internal
intermediate buffer */
if(iob->tail > iob->head) {
copysize = CURLMIN(len, iob->tail - iob->head);
memcpy(buf, iob->bufr + iob->head, copysize);
iob->head += copysize;
}
else
copysize = 0; /* buffer was allocated, but nothing was received */
/* Free intermediate buffer if it has no unprocessed data */
if(iob->head == iob->tail)
io_buffer_reset(iob);
return (ssize_t)copysize;
}
#endif /* USE_RECV_BEFORE_SEND_WORKAROUND */
static bool cf_socket_data_pending(struct Curl_cfilter *cf,
const struct Curl_easy *data)
{
struct cf_socket_ctx *ctx = cf->ctx;
int readable;
#ifdef USE_RECV_BEFORE_SEND_WORKAROUND
if(ctx->recv_buffer.bufr && ctx->recv_buffer.allc &&
ctx->recv_buffer.tail > ctx->recv_buffer.head)
return TRUE;
#endif
(void)data;
readable = SOCKET_READABLE(ctx->sock, 0);
return (readable > 0 && (readable & CURL_CSELECT_IN));
@ -1126,10 +1223,59 @@ static bool cf_socket_data_pending(struct Curl_cfilter *cf,
static ssize_t cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data,
const void *buf, size_t len, CURLcode *err)
{
struct cf_socket_ctx *ctx = cf->ctx;
ssize_t nwritten;
DEBUGASSERT(data->conn == cf->conn);
nwritten = Curl_send_plain(data, cf->sockindex, buf, len, err);
*err = CURLE_OK;
#ifdef USE_RECV_BEFORE_SEND_WORKAROUND
/* WinSock will destroy unread received data if send() is
failed.
To avoid lossage of received data, recv() must be
performed before every send() if any incoming data is
available. */
if(pre_receive_plain(cf, data)) {
*err = CURLE_OUT_OF_MEMORY;
return -1;
}
#endif
#if defined(MSG_FASTOPEN) && !defined(TCP_FASTOPEN_CONNECT) /* Linux */
if(cf->conn->bits.tcp_fastopen) {
bytes_written = sendto(ctx->sock, buf, len, MSG_FASTOPEN,
&cf->conn->remote_addr->sa_addr,
cf->conn->remote_addr->addrlen);
cf->conn->bits.tcp_fastopen = FALSE;
}
else
#endif
nwritten = swrite(ctx->sock, buf, len);
if(-1 == nwritten) {
int sockerr = SOCKERRNO;
if(
#ifdef WSAEWOULDBLOCK
/* This is how Windows does it */
(WSAEWOULDBLOCK == sockerr)
#else
/* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
due to its inability to send off data without blocking. We therefore
treat both error codes the same here */
(EWOULDBLOCK == sockerr) || (EAGAIN == sockerr) || (EINTR == sockerr) ||
(EINPROGRESS == sockerr)
#endif
) {
/* this is just a case of EWOULDBLOCK */
*err = CURLE_AGAIN;
}
else {
char buffer[STRERROR_LEN];
failf(data, "Send failure: %s",
Curl_strerror(sockerr, buffer, sizeof(buffer)));
data->state.os_errno = sockerr;
*err = CURLE_SEND_ERROR;
}
}
DEBUGF(LOG_CF(data, cf, "send(len=%zu) -> %d, err=%d",
len, (int)nwritten, *err));
return nwritten;
@ -1138,10 +1284,48 @@ static ssize_t cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data,
static ssize_t cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
char *buf, size_t len, CURLcode *err)
{
struct cf_socket_ctx *ctx = cf->ctx;
ssize_t nread;
DEBUGASSERT(data->conn == cf->conn);
nread = Curl_recv_plain(data, cf->sockindex, buf, len, err);
*err = CURLE_OK;
#ifdef USE_RECV_BEFORE_SEND_WORKAROUND
/* Check and return data that already received and storied in internal
intermediate buffer */
nread = get_pre_recved(cf, buf, len);
if(nread > 0) {
*err = CURLE_OK;
return nread;
}
#endif
nread = sread(ctx->sock, buf, len);
if(-1 == nread) {
int sockerr = SOCKERRNO;
if(
#ifdef WSAEWOULDBLOCK
/* This is how Windows does it */
(WSAEWOULDBLOCK == sockerr)
#else
/* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
due to its inability to send off data without blocking. We therefore
treat both error codes the same here */
(EWOULDBLOCK == sockerr) || (EAGAIN == sockerr) || (EINTR == sockerr)
#endif
) {
/* this is just a case of EWOULDBLOCK */
*err = CURLE_AGAIN;
}
else {
char buffer[STRERROR_LEN];
failf(data, "Recv failure: %s",
Curl_strerror(sockerr, buffer, sizeof(buffer)));
data->state.os_errno = sockerr;
*err = CURLE_RECV_ERROR;
}
}
DEBUGF(LOG_CF(data, cf, "recv(len=%zu) -> %d, err=%d", len, (int)nread,
*err));
return nread;

View File

@ -323,6 +323,14 @@ int Curl_conn_cf_get_select_socks(struct Curl_cfilter *cf,
return 0;
}
bool Curl_conn_cf_data_pending(struct Curl_cfilter *cf,
const struct Curl_easy *data)
{
if(cf)
return cf->cft->has_data_pending(cf, data);
return FALSE;
}
ssize_t Curl_conn_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data,
const void *buf, size_t len, CURLcode *err)
{
@ -426,8 +434,6 @@ bool Curl_conn_data_pending(struct Curl_easy *data, int sockindex)
(void)data;
DEBUGASSERT(data);
DEBUGASSERT(data->conn);
if(Curl_recv_has_postponed_data(data->conn, sockindex))
return TRUE;
cf = data->conn->cfilter[sockindex];
while(cf && !cf->connected) {

View File

@ -268,6 +268,8 @@ void Curl_conn_cf_close(struct Curl_cfilter *cf, struct Curl_easy *data);
int Curl_conn_cf_get_select_socks(struct Curl_cfilter *cf,
struct Curl_easy *data,
curl_socket_t *socks);
bool Curl_conn_cf_data_pending(struct Curl_cfilter *cf,
const struct Curl_easy *data);
ssize_t Curl_conn_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data,
const void *buf, size_t len, CURLcode *err);
ssize_t Curl_conn_cf_recv(struct Curl_cfilter *cf, struct Curl_easy *data,

View File

@ -1786,8 +1786,7 @@ static ssize_t h2_cf_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
if(ctx->inbuflen == 0) {
/* Receive data from the "lower" filters */
nread = Curl_conn_cf_recv(cf->next, data, ctx->inbuf, H2_BUFSIZE, err);
if(nread == -1) {
if(nread < 0) {
if(*err != CURLE_AGAIN)
failf(data, "Failed receiving HTTP2 data");
else if(stream->closed)
@ -1796,8 +1795,7 @@ static ssize_t h2_cf_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
return -1;
}
if(nread == 0) {
else if(nread == 0) {
if(!stream->closed) {
/* This will happen when the server or proxy server is SIGKILLed
during data transfer. We should emit an error since our data
@ -1814,21 +1812,22 @@ static ssize_t h2_cf_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
return 0;
}
H2BUGF(infof(data, "nread=%zd", nread));
H2BUGF(infof(data, "http2_recv: recvd %zd bytes", nread));
ctx->inbuflen = nread;
DEBUGASSERT(ctx->nread_inbuf == 0);
}
else {
nread = ctx->inbuflen - ctx->nread_inbuf;
(void)nread; /* silence warning, used in debug */
H2BUGF(infof(data, "Use data left in connection buffer, nread=%zd",
nread));
}
if(h2_process_pending_input(cf, data, err))
return -1;
if(Curl_conn_cf_data_pending(cf->next, data)) {
H2BUGF(infof(data, "conn has pending data, set drain"));
drain_this(cf, data);
}
}
if(stream->memlen) {
ssize_t retlen = stream->memlen;

View File

@ -46,6 +46,7 @@
#endif
#include "urldata.h"
#include "cfilters.h"
#include "cf-socket.h"
#include "curl_base64.h"
#include "ftp.h"
@ -455,15 +456,15 @@ static int ftp_send_command(struct Curl_easy *data, const char *message, ...)
/* Read |len| from the socket |fd| and store it in |to|. Return a CURLcode
saying whether an error occurred or CURLE_OK if |len| was read. */
static CURLcode
socket_read(struct Curl_easy *data, curl_socket_t fd, void *to, size_t len)
socket_read(struct Curl_easy *data, int sockindex, void *to, size_t len)
{
char *to_p = to;
CURLcode result;
ssize_t nread = 0;
while(len > 0) {
result = Curl_read_plain(data, fd, to_p, len, &nread);
if(!result) {
nread = Curl_conn_recv(data, sockindex, to_p, len, &result);
if(nread > 0) {
len -= nread;
to_p += nread;
}
@ -481,7 +482,7 @@ socket_read(struct Curl_easy *data, curl_socket_t fd, void *to, size_t len)
CURLcode saying whether an error occurred or CURLE_OK if |len| was
written. */
static CURLcode
socket_write(struct Curl_easy *data, curl_socket_t fd, const void *to,
socket_write(struct Curl_easy *data, int sockindex, const void *to,
size_t len)
{
const char *to_p = to;
@ -489,8 +490,8 @@ socket_write(struct Curl_easy *data, curl_socket_t fd, const void *to,
ssize_t written;
while(len > 0) {
result = Curl_write_plain(data, fd, to_p, len, &written);
if(!result) {
written = Curl_conn_send(data, sockindex, to_p, len, &result);
if(written > 0) {
len -= written;
to_p += written;
}
@ -503,7 +504,7 @@ socket_write(struct Curl_easy *data, curl_socket_t fd, const void *to,
return CURLE_OK;
}
static CURLcode read_data(struct Curl_easy *data, curl_socket_t fd,
static CURLcode read_data(struct Curl_easy *data, int sockindex,
struct krb5buffer *buf)
{
struct connectdata *conn = data->conn;
@ -511,7 +512,7 @@ static CURLcode read_data(struct Curl_easy *data, curl_socket_t fd,
CURLcode result;
int nread;
result = socket_read(data, fd, &len, sizeof(len));
result = socket_read(data, sockindex, &len, sizeof(len));
if(result)
return result;
@ -526,7 +527,7 @@ static CURLcode read_data(struct Curl_easy *data, curl_socket_t fd,
if(!len || !buf->data)
return CURLE_OUT_OF_MEMORY;
result = socket_read(data, fd, buf->data, len);
result = socket_read(data, sockindex, buf->data, len);
if(result)
return result;
nread = conn->mech->decode(conn->app_data, buf->data, len,
@ -555,13 +556,12 @@ static ssize_t sec_recv(struct Curl_easy *data, int sockindex,
size_t bytes_read;
size_t total_read = 0;
struct connectdata *conn = data->conn;
curl_socket_t fd = conn->sock[sockindex];
*err = CURLE_OK;
/* Handle clear text response. */
if(conn->sec_complete == 0 || conn->data_prot == PROT_CLEAR)
return Curl_recv_plain(data, sockindex, buffer, len, err);
return Curl_conn_recv(data, sockindex, buffer, len, err);
if(conn->in_buffer.eof_flag) {
conn->in_buffer.eof_flag = 0;
@ -574,7 +574,7 @@ static ssize_t sec_recv(struct Curl_easy *data, int sockindex,
buffer += bytes_read;
while(len > 0) {
if(read_data(data, fd, &conn->in_buffer))
if(read_data(data, sockindex, &conn->in_buffer))
return -1;
if(conn->in_buffer.size == 0) {
if(bytes_read > 0)

View File

@ -138,105 +138,6 @@ static size_t convert_lineends(struct Curl_easy *data,
}
#endif /* CURL_DO_LINEEND_CONV && !CURL_DISABLE_FTP */
#ifdef USE_RECV_BEFORE_SEND_WORKAROUND
bool Curl_recv_has_postponed_data(struct connectdata *conn, int sockindex)
{
struct postponed_data * const psnd = &(conn->postponed[sockindex]);
return psnd->buffer && psnd->allocated_size &&
psnd->recv_size > psnd->recv_processed;
}
static CURLcode pre_receive_plain(struct Curl_easy *data,
struct connectdata *conn, int num)
{
const curl_socket_t sockfd = conn->sock[num];
struct postponed_data * const psnd = &(conn->postponed[num]);
size_t bytestorecv = psnd->allocated_size - psnd->recv_size;
ssize_t recvedbytes;
/* WinSock will destroy unread received data if send() is
failed.
To avoid lossage of received data, recv() must be
performed before every send() if any incoming data is
available. However, skip this, if buffer is already full. */
if((conn->handler->protocol&PROTO_FAMILY_HTTP) != 0 &&
conn->recv[num] == Curl_conn_recv &&
(!psnd->buffer || bytestorecv)) {
const int readymask = Curl_socket_check(sockfd, CURL_SOCKET_BAD,
CURL_SOCKET_BAD, 0);
if(readymask != -1 && (readymask & CURL_CSELECT_IN) != 0) {
/* Have some incoming data */
if(!psnd->buffer) {
/* Use buffer double default size for intermediate buffer */
psnd->allocated_size = 2 * data->set.buffer_size;
psnd->buffer = malloc(psnd->allocated_size);
if(!psnd->buffer)
return CURLE_OUT_OF_MEMORY;
psnd->recv_size = 0;
psnd->recv_processed = 0;
#ifdef DEBUGBUILD
psnd->bindsock = sockfd; /* Used only for DEBUGASSERT */
#endif /* DEBUGBUILD */
bytestorecv = psnd->allocated_size;
}
DEBUGASSERT(psnd->bindsock == sockfd);
recvedbytes = sread(sockfd, psnd->buffer + psnd->recv_size,
bytestorecv);
if(recvedbytes > 0)
psnd->recv_size += recvedbytes;
}
}
return CURLE_OK;
}
static ssize_t get_pre_recved(struct connectdata *conn, int num, char *buf,
size_t len)
{
struct postponed_data * const psnd = &(conn->postponed[num]);
size_t copysize;
if(!psnd->buffer)
return 0;
DEBUGASSERT(psnd->allocated_size > 0);
DEBUGASSERT(psnd->recv_size <= psnd->allocated_size);
DEBUGASSERT(psnd->recv_processed <= psnd->recv_size);
/* Check and process data that already received and storied in internal
intermediate buffer */
if(psnd->recv_size > psnd->recv_processed) {
DEBUGASSERT(psnd->bindsock == conn->sock[num]);
copysize = CURLMIN(len, psnd->recv_size - psnd->recv_processed);
memcpy(buf, psnd->buffer + psnd->recv_processed, copysize);
psnd->recv_processed += copysize;
}
else
copysize = 0; /* buffer was allocated, but nothing was received */
/* Free intermediate buffer if it has no unprocessed data */
if(psnd->recv_processed == psnd->recv_size) {
free(psnd->buffer);
psnd->buffer = NULL;
psnd->allocated_size = 0;
psnd->recv_size = 0;
psnd->recv_processed = 0;
#ifdef DEBUGBUILD
psnd->bindsock = CURL_SOCKET_BAD;
#endif /* DEBUGBUILD */
}
return (ssize_t)copysize;
}
#else /* ! USE_RECV_BEFORE_SEND_WORKAROUND */
/* Use "do-nothing" macros instead of functions when workaround not used */
bool Curl_recv_has_postponed_data(struct connectdata *conn, int sockindex)
{
(void)conn;
(void)sockindex;
return false;
}
#define pre_receive_plain(d,c,n) CURLE_OK
#define get_pre_recved(c,n,b,l) 0
#endif /* ! USE_RECV_BEFORE_SEND_WORKAROUND */
/*
* Curl_write() is an internal write function that sends data to the
* server. Works with plain sockets, SCP, SSL or kerberos.
@ -294,154 +195,6 @@ CURLcode Curl_write(struct Curl_easy *data,
}
}
/* Curl_send_plain sends raw data without a size restriction on 'len'. */
ssize_t Curl_send_plain(struct Curl_easy *data, int num,
const void *mem, size_t len, CURLcode *code)
{
struct connectdata *conn;
curl_socket_t sockfd;
ssize_t bytes_written;
DEBUGASSERT(data);
DEBUGASSERT(data->conn);
conn = data->conn;
sockfd = conn->sock[num];
/* WinSock will destroy unread received data if send() is
failed.
To avoid lossage of received data, recv() must be
performed before every send() if any incoming data is
available. */
if(pre_receive_plain(data, conn, num)) {
*code = CURLE_OUT_OF_MEMORY;
return -1;
}
#if defined(MSG_FASTOPEN) && !defined(TCP_FASTOPEN_CONNECT) /* Linux */
if(conn->bits.tcp_fastopen) {
bytes_written = sendto(sockfd, mem, len, MSG_FASTOPEN,
&conn->remote_addr->sa_addr,
conn->remote_addr->addrlen);
conn->bits.tcp_fastopen = FALSE;
}
else
#endif
bytes_written = swrite(sockfd, mem, len);
*code = CURLE_OK;
if(-1 == bytes_written) {
int err = SOCKERRNO;
if(
#ifdef WSAEWOULDBLOCK
/* This is how Windows does it */
(WSAEWOULDBLOCK == err)
#else
/* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
due to its inability to send off data without blocking. We therefore
treat both error codes the same here */
(EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err) ||
(EINPROGRESS == err)
#endif
) {
/* this is just a case of EWOULDBLOCK */
*code = CURLE_AGAIN;
}
else {
char buffer[STRERROR_LEN];
failf(data, "Send failure: %s",
Curl_strerror(err, buffer, sizeof(buffer)));
data->state.os_errno = err;
*code = CURLE_SEND_ERROR;
}
}
return bytes_written;
}
/*
* Curl_write_plain() is an internal write function that sends data to the
* server using plain sockets only. Otherwise meant to have the exact same
* proto as Curl_write().
*
* This function wraps Curl_send_plain(). The only difference besides the
* prototype is '*written' (bytes written) is set to 0 on error.
* 'sockfd' must be one of the connection's two main sockets and the value of
* 'len' must not be changed.
*/
CURLcode Curl_write_plain(struct Curl_easy *data,
curl_socket_t sockfd,
const void *mem,
size_t len,
ssize_t *written)
{
CURLcode result;
struct connectdata *conn = data->conn;
int num;
DEBUGASSERT(conn);
DEBUGASSERT(sockfd == conn->sock[FIRSTSOCKET] ||
sockfd == conn->sock[SECONDARYSOCKET]);
if(sockfd != conn->sock[FIRSTSOCKET] &&
sockfd != conn->sock[SECONDARYSOCKET])
return CURLE_BAD_FUNCTION_ARGUMENT;
num = (sockfd == conn->sock[SECONDARYSOCKET]);
*written = Curl_send_plain(data, num, mem, len, &result);
if(*written == -1)
*written = 0;
return result;
}
/* Curl_recv_plain receives raw data without a size restriction on 'len'. */
ssize_t Curl_recv_plain(struct Curl_easy *data, int num, char *buf,
size_t len, CURLcode *code)
{
struct connectdata *conn;
curl_socket_t sockfd;
ssize_t nread;
DEBUGASSERT(data);
DEBUGASSERT(data->conn);
conn = data->conn;
sockfd = conn->sock[num];
/* Check and return data that already received and storied in internal
intermediate buffer */
nread = get_pre_recved(conn, num, buf, len);
if(nread > 0) {
*code = CURLE_OK;
return nread;
}
nread = sread(sockfd, buf, len);
*code = CURLE_OK;
if(-1 == nread) {
int err = SOCKERRNO;
if(
#ifdef WSAEWOULDBLOCK
/* This is how Windows does it */
(WSAEWOULDBLOCK == err)
#else
/* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
due to its inability to send off data without blocking. We therefore
treat both error codes the same here */
(EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err)
#endif
) {
/* this is just a case of EWOULDBLOCK */
*code = CURLE_AGAIN;
}
else {
char buffer[STRERROR_LEN];
failf(data, "Recv failure: %s",
Curl_strerror(err, buffer, sizeof(buffer)));
data->state.os_errno = err;
*code = CURLE_RECV_ERROR;
}
}
return nread;
}
static CURLcode pausewrite(struct Curl_easy *data,
int type, /* what type of data */
const char *ptr,
@ -633,41 +386,6 @@ CURLcode Curl_client_write(struct Curl_easy *data,
return chop_write(data, type, ptr, len);
}
/*
* Curl_read_plain() is an internal read function that reads data from the
* server using plain sockets only. Otherwise meant to have the exact same
* proto as Curl_read().
*
* This function wraps Curl_recv_plain(). The only difference besides the
* prototype is '*n' (bytes read) is set to 0 on error.
* 'sockfd' must be one of the connection's two main sockets and the value of
* 'sizerequested' must not be changed.
*/
CURLcode Curl_read_plain(struct Curl_easy *data, /* transfer */
curl_socket_t sockfd, /* read from this socket */
char *buf, /* store read data here */
size_t sizerequested, /* max amount to read */
ssize_t *n) /* amount bytes read */
{
CURLcode result;
struct connectdata *conn = data->conn;
int num;
DEBUGASSERT(conn);
DEBUGASSERT(sockfd == conn->sock[FIRSTSOCKET] ||
sockfd == conn->sock[SECONDARYSOCKET]);
if(sockfd != conn->sock[FIRSTSOCKET] &&
sockfd != conn->sock[SECONDARYSOCKET])
return CURLE_BAD_FUNCTION_ARGUMENT;
num = (sockfd == conn->sock[SECONDARYSOCKET]);
*n = Curl_recv_plain(data, num, buf, sizerequested, &result);
if(*n == -1)
*n = 0;
return result;
}
/*
* Internal read-from-socket function. This is meant to deal with plain
* sockets, SSL sockets and kerberos sockets.

View File

@ -40,20 +40,6 @@
CURLcode Curl_client_write(struct Curl_easy *data, int type, char *ptr,
size_t len) WARN_UNUSED_RESULT;
bool Curl_recv_has_postponed_data(struct connectdata *conn, int sockindex);
/* internal read-function, does plain socket only */
CURLcode Curl_read_plain(struct Curl_easy *data,
curl_socket_t sockfd,
char *buf,
size_t sizerequested,
ssize_t *n);
ssize_t Curl_recv_plain(struct Curl_easy *data, int num, char *buf,
size_t len, CURLcode *code);
ssize_t Curl_send_plain(struct Curl_easy *data, int num,
const void *mem, size_t len, CURLcode *code);
/* internal read-function, does plain socket, SSL and krb4 */
CURLcode Curl_read(struct Curl_easy *data, curl_socket_t sockfd,
char *buf, size_t buffersize,
@ -65,10 +51,4 @@ CURLcode Curl_write(struct Curl_easy *data,
const void *mem, size_t len,
ssize_t *written);
/* internal write-function, does plain sockets ONLY */
CURLcode Curl_write_plain(struct Curl_easy *data,
curl_socket_t sockfd,
const void *mem, size_t len,
ssize_t *written);
#endif /* HEADER_CURL_SENDF_H */

View File

@ -89,8 +89,8 @@ struct socks_state {
*
* This is STUPID BLOCKING behavior. Only used by the SOCKS GSSAPI functions.
*/
int Curl_blockread_all(struct Curl_easy *data, /* transfer */
curl_socket_t sockfd, /* read from this socket */
int Curl_blockread_all(struct Curl_cfilter *cf,
struct Curl_easy *data, /* transfer */
char *buf, /* store read data here */
ssize_t buffersize, /* max amount to read */
ssize_t *n) /* amount bytes read */
@ -98,6 +98,8 @@ int Curl_blockread_all(struct Curl_easy *data, /* transfer */
ssize_t nread = 0;
ssize_t allread = 0;
int result;
CURLcode err = CURLE_OK;
*n = 0;
for(;;) {
timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
@ -108,15 +110,19 @@ int Curl_blockread_all(struct Curl_easy *data, /* transfer */
}
if(!timeout_ms)
timeout_ms = TIMEDIFF_T_MAX;
if(SOCKET_READABLE(sockfd, timeout_ms) <= 0) {
if(SOCKET_READABLE(cf->conn->sock[cf->sockindex], timeout_ms) <= 0) {
result = ~CURLE_OK;
break;
}
result = Curl_read_plain(data, sockfd, buf, buffersize, &nread);
if(CURLE_AGAIN == result)
continue;
if(result)
break;
nread = Curl_conn_cf_recv(cf->next, data, buf, buffersize, &err);
if(nread <= 0) {
result = err;
if(CURLE_AGAIN == err)
continue;
if(err) {
break;
}
}
if(buffersize == nread) {
allread += nread;
@ -192,6 +198,68 @@ static void socksstate(struct socks_state *sx, struct Curl_easy *data,
#endif
}
static CURLproxycode socks_state_send(struct Curl_cfilter *cf,
struct socks_state *sx,
struct Curl_easy *data,
CURLproxycode failcode,
const char *description)
{
ssize_t nwritten;
CURLcode result;
nwritten = Curl_conn_cf_send(cf->next, data, (char *)sx->outp,
sx->outstanding, &result);
if(nwritten <= 0) {
if(CURLE_AGAIN == result) {
return CURLPX_OK;
}
else if(CURLE_OK == result) {
/* connection closed */
failf(data, "connection to proxy closed");
return CURLPX_CLOSED;
}
failf(data, "Failed to send %s: %s", description,
curl_easy_strerror(result));
return failcode;
}
DEBUGASSERT(sx->outstanding >= nwritten);
/* not done, remain in state */
sx->outstanding -= nwritten;
sx->outp += nwritten;
return CURLPX_OK;
}
static CURLproxycode socks_state_recv(struct Curl_cfilter *cf,
struct socks_state *sx,
struct Curl_easy *data,
CURLproxycode failcode,
const char *description)
{
ssize_t nread;
CURLcode result;
nread = Curl_conn_cf_recv(cf->next, data, (char *)sx->outp,
sx->outstanding, &result);
if(nread <= 0) {
if(CURLE_AGAIN == result) {
return CURLPX_OK;
}
else if(CURLE_OK == result) {
/* connection closed */
failf(data, "connection to proxy closed");
return CURLPX_CLOSED;
}
failf(data, "SOCKS4: Failed receiving %s: %s", description,
curl_easy_strerror(result));
return failcode;
}
/* remain in reading state */
DEBUGASSERT(sx->outstanding >= nread);
sx->outstanding -= nread;
sx->outp += nread;
return CURLPX_OK;
}
/*
* This function logs in to a SOCKS4 proxy and sends the specifics to the final
* destination server.
@ -212,10 +280,8 @@ static CURLproxycode do_SOCKS4(struct Curl_cfilter *cf,
(conn->socks_proxy.proxytype == CURLPROXY_SOCKS4A) ? TRUE : FALSE;
unsigned char *socksreq = (unsigned char *)data->state.buffer;
CURLcode result;
curl_socket_t sockfd = conn->sock[cf->sockindex];
CURLproxycode presult;
struct Curl_dns_entry *dns = NULL;
ssize_t actualread;
ssize_t written;
/* make sure that the buffer is at least 600 bytes */
DEBUGASSERT(READBUFFER_MIN >= 600);
@ -375,19 +441,14 @@ static CURLproxycode do_SOCKS4(struct Curl_cfilter *cf,
/* FALLTHROUGH */
case CONNECT_REQ_SENDING:
/* Send request */
result = Curl_write_plain(data, sockfd, (char *)sx->outp,
sx->outstanding, &written);
if(result && (CURLE_AGAIN != result)) {
failf(data, "Failed to send SOCKS4 connect request.");
return CURLPX_SEND_CONNECT;
}
if(written != sx->outstanding) {
/* not done, remain in state */
sx->outstanding -= written;
sx->outp += written;
presult = socks_state_send(cf, sx, data, CURLPX_SEND_CONNECT,
"SOCKS4 connect request");
if(CURLPX_OK != presult)
return presult;
else if(sx->outstanding) {
/* remain in sending state */
return CURLPX_OK;
}
/* done sending! */
sx->outstanding = 8; /* receive data size */
sx->outp = socksreq;
@ -396,22 +457,12 @@ static CURLproxycode do_SOCKS4(struct Curl_cfilter *cf,
/* FALLTHROUGH */
case CONNECT_SOCKS_READ:
/* Receive response */
result = Curl_read_plain(data, sockfd, (char *)sx->outp,
sx->outstanding, &actualread);
if(result && (CURLE_AGAIN != result)) {
failf(data, "SOCKS4: Failed receiving connect request ack: %s",
curl_easy_strerror(result));
return CURLPX_RECV_CONNECT;
}
else if(!result && !actualread) {
/* connection closed */
failf(data, "connection to proxy closed");
return CURLPX_CLOSED;
}
else if(actualread != sx->outstanding) {
presult = socks_state_recv(cf, sx, data, CURLPX_RECV_CONNECT,
"connect request ack");
if(CURLPX_OK != presult)
return presult;
else if(sx->outstanding) {
/* remain in reading state */
sx->outstanding -= actualread;
sx->outp += actualread;
return CURLPX_OK;
}
sxstate(sx, data, CONNECT_DONE);
@ -518,10 +569,8 @@ static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf,
unsigned char *socksreq = (unsigned char *)data->state.buffer;
char dest[256] = "unknown"; /* printable hostname:port */
int idx;
ssize_t actualread;
ssize_t written;
CURLcode result;
curl_socket_t sockfd = conn->sock[cf->sockindex];
CURLproxycode presult;
bool socks5_resolve_local =
(conn->socks_proxy.proxytype == CURLPROXY_SOCKS5) ? TRUE : FALSE;
const size_t hostname_len = strlen(sx->hostname);
@ -567,30 +616,25 @@ static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf,
/* write the number of authentication methods */
socksreq[1] = (unsigned char) (idx - 2);
result = Curl_write_plain(data, sockfd, socksreq, idx, &written);
if(result && (CURLE_AGAIN != result)) {
failf(data, "Unable to send initial SOCKS5 request.");
return CURLPX_SEND_CONNECT;
}
if(written != idx) {
sxstate(sx, data, CONNECT_SOCKS_SEND);
sx->outstanding = idx - written;
sx->outp = &socksreq[written];
sx->outp = socksreq;
sx->outstanding = idx;
presult = socks_state_send(cf, sx, data, CURLPX_SEND_CONNECT,
"initial SOCKS5 request");
if(CURLPX_OK != presult)
return presult;
else if(sx->outstanding) {
/* remain in sending state */
return CURLPX_OK;
}
sxstate(sx, data, CONNECT_SOCKS_READ);
goto CONNECT_SOCKS_READ_INIT;
case CONNECT_SOCKS_SEND:
result = Curl_write_plain(data, sockfd, (char *)sx->outp,
sx->outstanding, &written);
if(result && (CURLE_AGAIN != result)) {
failf(data, "Unable to send initial SOCKS5 request.");
return CURLPX_SEND_CONNECT;
}
if(written != sx->outstanding) {
/* not done, remain in state */
sx->outstanding -= written;
sx->outp += written;
presult = socks_state_send(cf, sx, data, CURLPX_SEND_CONNECT,
"initial SOCKS5 request");
if(CURLPX_OK != presult)
return presult;
else if(sx->outstanding) {
/* remain in sending state */
return CURLPX_OK;
}
/* FALLTHROUGH */
@ -600,21 +644,12 @@ static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf,
sx->outp = socksreq; /* store it here */
/* FALLTHROUGH */
case CONNECT_SOCKS_READ:
result = Curl_read_plain(data, sockfd, (char *)sx->outp,
sx->outstanding, &actualread);
if(result && (CURLE_AGAIN != result)) {
failf(data, "Unable to receive initial SOCKS5 response.");
return CURLPX_RECV_CONNECT;
}
else if(!result && !actualread) {
/* connection closed */
failf(data, "Connection to proxy closed");
return CURLPX_CLOSED;
}
else if(actualread != sx->outstanding) {
presult = socks_state_recv(cf, sx, data, CURLPX_RECV_CONNECT,
"initial SOCKS5 response");
if(CURLPX_OK != presult)
return presult;
else if(sx->outstanding) {
/* remain in reading state */
sx->outstanding -= actualread;
sx->outp += actualread;
return CURLPX_OK;
}
else if(socksreq[0] != 5) {
@ -634,7 +669,7 @@ static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf,
#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
else if(allow_gssapi && (socksreq[1] == 1)) {
sxstate(sx, data, CONNECT_GSSAPI_INIT);
result = Curl_SOCKS5_gssapi_negotiate(cf->sockindex, data);
result = Curl_SOCKS5_gssapi_negotiate(cf, data);
if(result) {
failf(data, "Unable to negotiate SOCKS5 GSS-API context.");
return CURLPX_GSSAPI;
@ -713,16 +748,12 @@ static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf,
}
/* FALLTHROUGH */
case CONNECT_AUTH_SEND:
result = Curl_write_plain(data, sockfd, sx->outp,
sx->outstanding, &written);
if(result && (CURLE_AGAIN != result)) {
failf(data, "Failed to send SOCKS5 sub-negotiation request.");
return CURLPX_SEND_AUTH;
}
if(sx->outstanding != written) {
/* remain in state */
sx->outstanding -= written;
sx->outp += written;
presult = socks_state_send(cf, sx, data, CURLPX_SEND_AUTH,
"SOCKS5 sub-negotiation request");
if(CURLPX_OK != presult)
return presult;
else if(sx->outstanding) {
/* remain in sending state */
return CURLPX_OK;
}
sx->outp = socksreq;
@ -730,21 +761,12 @@ static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf,
sxstate(sx, data, CONNECT_AUTH_READ);
/* FALLTHROUGH */
case CONNECT_AUTH_READ:
result = Curl_read_plain(data, sockfd, (char *)sx->outp,
sx->outstanding, &actualread);
if(result && (CURLE_AGAIN != result)) {
failf(data, "Unable to receive SOCKS5 sub-negotiation response.");
return CURLPX_RECV_AUTH;
}
else if(!result && !actualread) {
/* connection closed */
failf(data, "connection to proxy closed");
return CURLPX_CLOSED;
}
else if(actualread != sx->outstanding) {
/* remain in state */
sx->outstanding -= actualread;
sx->outp += actualread;
presult = socks_state_recv(cf, sx, data, CURLPX_RECV_AUTH,
"SOCKS5 sub-negotiation response");
if(CURLPX_OK != presult)
return presult;
else if(sx->outstanding) {
/* remain in reading state */
return CURLPX_OK;
}
/* ignore the first (VER) byte */
@ -909,16 +931,12 @@ static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf,
sxstate(sx, data, CONNECT_REQ_SENDING);
/* FALLTHROUGH */
case CONNECT_REQ_SENDING:
result = Curl_write_plain(data, sockfd, (char *)sx->outp,
sx->outstanding, &written);
if(result && (CURLE_AGAIN != result)) {
failf(data, "Failed to send SOCKS5 connect request.");
return CURLPX_SEND_REQUEST;
}
if(sx->outstanding != written) {
/* remain in state */
sx->outstanding -= written;
sx->outp += written;
presult = socks_state_send(cf, sx, data, CURLPX_SEND_REQUEST,
"SOCKS5 connect request");
if(CURLPX_OK != presult)
return presult;
else if(sx->outstanding) {
/* remain in send state */
return CURLPX_OK;
}
#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
@ -932,25 +950,15 @@ static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf,
sxstate(sx, data, CONNECT_REQ_READ);
/* FALLTHROUGH */
case CONNECT_REQ_READ:
result = Curl_read_plain(data, sockfd, (char *)sx->outp,
sx->outstanding, &actualread);
if(result && (CURLE_AGAIN != result)) {
failf(data, "Failed to receive SOCKS5 connect request ack.");
return CURLPX_RECV_REQACK;
}
else if(!result && !actualread) {
/* connection closed */
failf(data, "connection to proxy closed");
return CURLPX_CLOSED;
}
else if(actualread != sx->outstanding) {
/* remain in state */
sx->outstanding -= actualread;
sx->outp += actualread;
presult = socks_state_recv(cf, sx, data, CURLPX_RECV_REQACK,
"SOCKS5 connect request ack");
if(CURLPX_OK != presult)
return presult;
else if(sx->outstanding) {
/* remain in reading state */
return CURLPX_OK;
}
if(socksreq[0] != 5) { /* version */
else if(socksreq[0] != 5) { /* version */
failf(data,
"SOCKS5 reply has wrong version, version should be 5.");
return CURLPX_BAD_VERSION;
@ -1031,21 +1039,12 @@ static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf,
#endif
/* FALLTHROUGH */
case CONNECT_REQ_READ_MORE:
result = Curl_read_plain(data, sockfd, (char *)sx->outp,
sx->outstanding, &actualread);
if(result && (CURLE_AGAIN != result)) {
failf(data, "Failed to receive SOCKS5 connect request ack.");
return CURLPX_RECV_ADDRESS;
}
else if(!result && !actualread) {
/* connection closed */
failf(data, "connection to proxy closed");
return CURLPX_CLOSED;
}
else if(actualread != sx->outstanding) {
/* remain in state */
sx->outstanding -= actualread;
sx->outp += actualread;
presult = socks_state_recv(cf, sx, data, CURLPX_RECV_ADDRESS,
"SOCKS5 connect request address");
if(CURLPX_OK != presult)
return presult;
else if(sx->outstanding) {
/* remain in reading state */
return CURLPX_OK;
}
sxstate(sx, data, CONNECT_DONE);

View File

@ -37,8 +37,8 @@
*
* This is STUPID BLOCKING behavior
*/
int Curl_blockread_all(struct Curl_easy *data,
curl_socket_t sockfd,
int Curl_blockread_all(struct Curl_cfilter *cf,
struct Curl_easy *data,
char *buf,
ssize_t buffersize,
ssize_t *n);
@ -47,7 +47,7 @@ int Curl_blockread_all(struct Curl_easy *data,
/*
* This function handles the SOCKS5 GSS-API negotiation and initialization
*/
CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
struct Curl_easy *data);
#endif

View File

@ -30,6 +30,7 @@
#include "curl_gssapi.h"
#include "urldata.h"
#include "sendf.h"
#include "cfilters.h"
#include "connect.h"
#include "timeval.h"
#include "socks.h"
@ -101,14 +102,14 @@ static int check_gss_err(struct Curl_easy *data,
return 0;
}
CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct connectdata *conn = data->conn;
curl_socket_t sock = conn->sock[sockindex];
struct connectdata *conn = cf->conn;
curl_socket_t sock = conn->sock[cf->sockindex];
CURLcode code;
ssize_t actualread;
ssize_t written;
ssize_t nwritten;
int result;
OM_uint32 gss_major_status, gss_minor_status, gss_status;
OM_uint32 gss_ret_flags;
@ -203,8 +204,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
us_length = htons((short)gss_send_token.length);
memcpy(socksreq + 2, &us_length, sizeof(short));
code = Curl_write_plain(data, sock, (char *)socksreq, 4, &written);
if(code || (4 != written)) {
nwritten = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, &code);
if(code || (4 != nwritten)) {
failf(data, "Failed to send GSS-API authentication request.");
gss_release_name(&gss_status, &server);
gss_release_buffer(&gss_status, &gss_recv_token);
@ -213,10 +214,10 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
return CURLE_COULDNT_CONNECT;
}
code = Curl_write_plain(data, sock, (char *)gss_send_token.value,
gss_send_token.length, &written);
if(code || ((ssize_t)gss_send_token.length != written)) {
nwritten = Curl_conn_cf_send(cf->next, data,
(char *)gss_send_token.value,
gss_send_token.length, &code);
if(code || ((ssize_t)gss_send_token.length != nwritten)) {
failf(data, "Failed to send GSS-API authentication token.");
gss_release_name(&gss_status, &server);
gss_release_buffer(&gss_status, &gss_recv_token);
@ -242,7 +243,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
* +----+------+-----+----------------+
*/
result = Curl_blockread_all(data, sock, (char *)socksreq, 4, &actualread);
result = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread);
if(result || (actualread != 4)) {
failf(data, "Failed to receive GSS-API authentication response.");
gss_release_name(&gss_status, &server);
@ -281,7 +282,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
return CURLE_OUT_OF_MEMORY;
}
result = Curl_blockread_all(data, sock, (char *)gss_recv_token.value,
result = Curl_blockread_all(cf, data, (char *)gss_recv_token.value,
gss_recv_token.length, &actualread);
if(result || (actualread != us_length)) {
@ -410,8 +411,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
memcpy(socksreq + 2, &us_length, sizeof(short));
}
code = Curl_write_plain(data, sock, (char *)socksreq, 4, &written);
if(code || (4 != written)) {
nwritten = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, &code);
if(code || (4 != nwritten)) {
failf(data, "Failed to send GSS-API encryption request.");
gss_release_buffer(&gss_status, &gss_w_token);
gss_delete_sec_context(&gss_status, &gss_context, NULL);
@ -420,17 +421,18 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
if(data->set.socks5_gssapi_nec) {
memcpy(socksreq, &gss_enc, 1);
code = Curl_write_plain(data, sock, socksreq, 1, &written);
if(code || ( 1 != written)) {
nwritten = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 1, &code);
if(code || ( 1 != nwritten)) {
failf(data, "Failed to send GSS-API encryption type.");
gss_delete_sec_context(&gss_status, &gss_context, NULL);
return CURLE_COULDNT_CONNECT;
}
}
else {
code = Curl_write_plain(data, sock, (char *)gss_w_token.value,
gss_w_token.length, &written);
if(code || ((ssize_t)gss_w_token.length != written)) {
nwritten = Curl_conn_cf_send(cf->next, data,
(char *)gss_w_token.value,
gss_w_token.length, &code);
if(code || ((ssize_t)gss_w_token.length != nwritten)) {
failf(data, "Failed to send GSS-API encryption type.");
gss_release_buffer(&gss_status, &gss_w_token);
gss_delete_sec_context(&gss_status, &gss_context, NULL);
@ -439,7 +441,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
gss_release_buffer(&gss_status, &gss_w_token);
}
result = Curl_blockread_all(data, sock, (char *)socksreq, 4, &actualread);
result = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread);
if(result || (actualread != 4)) {
failf(data, "Failed to receive GSS-API encryption response.");
gss_delete_sec_context(&gss_status, &gss_context, NULL);
@ -470,7 +472,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
gss_delete_sec_context(&gss_status, &gss_context, NULL);
return CURLE_OUT_OF_MEMORY;
}
result = Curl_blockread_all(data, sock, (char *)gss_recv_token.value,
result = Curl_blockread_all(cf, data, (char *)gss_recv_token.value,
gss_recv_token.length, &actualread);
if(result || (actualread != us_length)) {

View File

@ -29,6 +29,7 @@
#include "urldata.h"
#include "sendf.h"
#include "cfilters.h"
#include "connect.h"
#include "strerror.h"
#include "timeval.h"
@ -62,11 +63,11 @@ static int check_sspi_err(struct Curl_easy *data,
}
/* This is the SSPI-using version of this function */
CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct connectdata *conn = data->conn;
curl_socket_t sock = conn->sock[sockindex];
struct connectdata *conn = cf->conn;
curl_socket_t sock = conn->sock[cf->sockindex];
CURLcode code;
ssize_t actualread;
ssize_t written;
@ -206,7 +207,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
us_length = htons((short)sspi_send_token.cbBuffer);
memcpy(socksreq + 2, &us_length, sizeof(short));
code = Curl_write_plain(data, sock, (char *)socksreq, 4, &written);
written = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, &code);
if(code || (4 != written)) {
failf(data, "Failed to send SSPI authentication request.");
free(service_name);
@ -219,8 +220,9 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
return CURLE_COULDNT_CONNECT;
}
code = Curl_write_plain(data, sock, (char *)sspi_send_token.pvBuffer,
sspi_send_token.cbBuffer, &written);
written = Curl_conn_cf_send(cf->next, data,
(char *)sspi_send_token.pvBuffer,
sspi_send_token.cbBuffer, &code);
if(code || (sspi_send_token.cbBuffer != (size_t)written)) {
failf(data, "Failed to send SSPI authentication token.");
free(service_name);
@ -260,7 +262,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
* +----+------+-----+----------------+
*/
result = Curl_blockread_all(data, sock, (char *)socksreq, 4, &actualread);
result = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread);
if(result || (actualread != 4)) {
failf(data, "Failed to receive SSPI authentication response.");
free(service_name);
@ -300,7 +302,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
s_pSecFn->DeleteSecurityContext(&sspi_context);
return CURLE_OUT_OF_MEMORY;
}
result = Curl_blockread_all(data, sock, (char *)sspi_recv_token.pvBuffer,
result = Curl_blockread_all(cf, data, (char *)sspi_recv_token.pvBuffer,
sspi_recv_token.cbBuffer, &actualread);
if(result || (actualread != us_length)) {
@ -468,7 +470,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
memcpy(socksreq + 2, &us_length, sizeof(short));
}
code = Curl_write_plain(data, sock, (char *)socksreq, 4, &written);
written = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, &code);
if(code || (4 != written)) {
failf(data, "Failed to send SSPI encryption request.");
if(sspi_send_token.pvBuffer)
@ -479,7 +481,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
if(data->set.socks5_gssapi_nec) {
memcpy(socksreq, &gss_enc, 1);
code = Curl_write_plain(data, sock, (char *)socksreq, 1, &written);
written = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 1, &code);
if(code || (1 != written)) {
failf(data, "Failed to send SSPI encryption type.");
s_pSecFn->DeleteSecurityContext(&sspi_context);
@ -487,8 +489,9 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
}
}
else {
code = Curl_write_plain(data, sock, (char *)sspi_send_token.pvBuffer,
sspi_send_token.cbBuffer, &written);
written = Curl_conn_cf_send(cf->next, data,
(char *)sspi_send_token.pvBuffer,
sspi_send_token.cbBuffer, &code);
if(code || (sspi_send_token.cbBuffer != (size_t)written)) {
failf(data, "Failed to send SSPI encryption type.");
if(sspi_send_token.pvBuffer)
@ -500,7 +503,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
}
result = Curl_blockread_all(data, sock, (char *)socksreq, 4, &actualread);
result = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread);
if(result || (actualread != 4)) {
failf(data, "Failed to receive SSPI encryption response.");
s_pSecFn->DeleteSecurityContext(&sspi_context);
@ -532,7 +535,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
return CURLE_OUT_OF_MEMORY;
}
result = Curl_blockread_all(data, sock, (char *)sspi_w_token[0].pvBuffer,
result = Curl_blockread_all(cf, data, (char *)sspi_w_token[0].pvBuffer,
sspi_w_token[0].cbBuffer, &actualread);
if(result || (actualread != us_length)) {

View File

@ -705,45 +705,6 @@ CURLcode Curl_open(struct Curl_easy **curl)
return result;
}
#ifdef USE_RECV_BEFORE_SEND_WORKAROUND
static void conn_reset_postponed_data(struct connectdata *conn, int num)
{
struct postponed_data * const psnd = &(conn->postponed[num]);
if(psnd->buffer) {
DEBUGASSERT(psnd->allocated_size > 0);
DEBUGASSERT(psnd->recv_size <= psnd->allocated_size);
DEBUGASSERT(psnd->recv_size ?
(psnd->recv_processed < psnd->recv_size) :
(psnd->recv_processed == 0));
DEBUGASSERT(psnd->bindsock != CURL_SOCKET_BAD);
free(psnd->buffer);
psnd->buffer = NULL;
psnd->allocated_size = 0;
psnd->recv_size = 0;
psnd->recv_processed = 0;
#ifdef DEBUGBUILD
psnd->bindsock = CURL_SOCKET_BAD; /* used only for DEBUGASSERT */
#endif /* DEBUGBUILD */
}
else {
DEBUGASSERT(psnd->allocated_size == 0);
DEBUGASSERT(psnd->recv_size == 0);
DEBUGASSERT(psnd->recv_processed == 0);
DEBUGASSERT(psnd->bindsock == CURL_SOCKET_BAD);
}
}
static void conn_reset_all_postponed_data(struct connectdata *conn)
{
conn_reset_postponed_data(conn, 0);
conn_reset_postponed_data(conn, 1);
}
#else /* ! USE_RECV_BEFORE_SEND_WORKAROUND */
/* Use "do-nothing" macro instead of function when workaround not used */
#define conn_reset_all_postponed_data(c) do {} while(0)
#endif /* ! USE_RECV_BEFORE_SEND_WORKAROUND */
static void conn_shutdown(struct Curl_easy *data)
{
DEBUGASSERT(data);
@ -792,7 +753,6 @@ static void conn_free(struct Curl_easy *data, struct connectdata *conn)
Curl_safefree(conn->hostname_resolve);
Curl_safefree(conn->secondaryhostname);
conn_reset_all_postponed_data(conn);
Curl_llist_destroy(&conn->easyq, NULL);
Curl_safefree(conn->localdev);
Curl_free_primary_ssl_config(&conn->ssl_config);
@ -1545,10 +1505,6 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
conn->connection_id = -1; /* no ID */
conn->port = -1; /* unknown at this point */
conn->remote_port = -1; /* unknown at this point */
#if defined(USE_RECV_BEFORE_SEND_WORKAROUND) && defined(DEBUGBUILD)
conn->postponed[0].bindsock = CURL_SOCKET_BAD; /* no file descriptor */
conn->postponed[1].bindsock = CURL_SOCKET_BAD; /* no file descriptor */
#endif /* USE_RECV_BEFORE_SEND_WORKAROUND && DEBUGBUILD */
/* Default protocol-independent behavior doesn't support persistent
connections, so we set this to force-close. Protocols that support
@ -3399,8 +3355,6 @@ static void reuse_conn(struct Curl_easy *data,
existing->hostname_resolve = temp->hostname_resolve;
temp->hostname_resolve = NULL;
conn_reset_all_postponed_data(temp); /* free buffers */
/* re-use init */
existing->bits.reuse = TRUE; /* yes, we're re-using here */

View File

@ -830,20 +830,6 @@ struct Curl_handler {
#define CONNRESULT_NONE 0 /* No extra information. */
#define CONNRESULT_DEAD (1<<0) /* The connection is dead. */
#ifdef USE_RECV_BEFORE_SEND_WORKAROUND
struct postponed_data {
char *buffer; /* Temporal store for received data during
sending, must be freed */
size_t allocated_size; /* Size of temporal store */
size_t recv_size; /* Size of received data during sending */
size_t recv_processed; /* Size of processed part of postponed data */
#ifdef DEBUGBUILD
curl_socket_t bindsock;/* Structure must be bound to specific socket,
used only for DEBUGASSERT */
#endif /* DEBUGBUILD */
};
#endif /* USE_RECV_BEFORE_SEND_WORKAROUND */
struct proxy_info {
struct hostname host;
int port;
@ -926,9 +912,6 @@ struct connectdata {
Curl_send *send[2];
struct Curl_cfilter *cfilter[2]; /* connection filters */
#ifdef USE_RECV_BEFORE_SEND_WORKAROUND
struct postponed_data postponed[2]; /* two buffers for two sockets */
#endif /* USE_RECV_BEFORE_SEND_WORKAROUND */
struct ssl_primary_config ssl_config;
#ifndef CURL_DISABLE_PROXY
struct ssl_primary_config proxy_ssl_config;

View File

@ -179,8 +179,8 @@ struct ssl_backend_data {
size_t encdata_offset, decdata_offset;
unsigned char *encdata_buffer, *decdata_buffer;
/* encdata_is_incomplete: if encdata contains only a partial record that
can't be decrypted without another Curl_read_plain (that is, status is
SEC_E_INCOMPLETE_MESSAGE) then set this true. after Curl_read_plain writes
can't be decrypted without another recv() (that is, status is
SEC_E_INCOMPLETE_MESSAGE) then set this true. after an recv() adds
more bytes into encdata then set this back to false. */
bool encdata_is_incomplete;
unsigned long req_flags, ret_flags;