mirror of
https://github.com/curl/curl.git
synced 2025-04-12 16:20:35 +08:00
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:
parent
a3bcfab4b5
commit
5651a36d1a
192
lib/cf-socket.c
192
lib/cf-socket.c
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
|
15
lib/http2.c
15
lib/http2.c
@ -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;
|
||||
|
24
lib/krb5.c
24
lib/krb5.c
@ -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)
|
||||
|
282
lib/sendf.c
282
lib/sendf.c
@ -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.
|
||||
|
20
lib/sendf.h
20
lib/sendf.h
@ -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 */
|
||||
|
281
lib/socks.c
281
lib/socks.c
@ -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);
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)) {
|
||||
|
@ -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)) {
|
||||
|
46
lib/url.c
46
lib/url.c
@ -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 */
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user