psl.c \
rand.c \
rename.c \
+ request.c \
rtsp.c \
select.c \
sendf.c \
psl.h \
rand.h \
rename.h \
+ request.h \
rtsp.h \
select.h \
sendf.h \
#include <hyper.h>
#include "urldata.h"
+#include "cfilters.h"
#include "sendf.h"
#include "headers.h"
#include "transfer.h"
size_t Curl_hyper_recv(void *userp, hyper_context *ctx,
uint8_t *buf, size_t buflen)
{
- struct Curl_easy *data = userp;
+ struct hyp_io_ctx *io_ctx = userp;
+ struct Curl_easy *data = io_ctx->data;
struct connectdata *conn = data->conn;
CURLcode result;
ssize_t nread;
(void)ctx;
DEBUGF(infof(data, "Curl_hyper_recv(%zu)", buflen));
- result = Curl_read(data, conn->sockfd, (char *)buf, buflen, &nread);
+ result = Curl_conn_recv(data, io_ctx->sockindex,
+ (char *)buf, buflen, &nread);
if(result == CURLE_AGAIN) {
/* would block, register interest */
DEBUGF(infof(data, "Curl_hyper_recv(%zu) -> EAGAIN", buflen));
size_t Curl_hyper_send(void *userp, hyper_context *ctx,
const uint8_t *buf, size_t buflen)
{
- struct Curl_easy *data = userp;
- struct connectdata *conn = data->conn;
+ struct hyp_io_ctx *io_ctx = userp;
+ struct Curl_easy *data = io_ctx->data;
CURLcode result;
ssize_t nwrote;
DEBUGF(infof(data, "Curl_hyper_send(%zu)", buflen));
- result = Curl_write(data, conn->sockfd, (void *)buf, buflen, &nwrote);
- if(!result && !nwrote)
- result = CURLE_AGAIN;
+ result = Curl_conn_send(data, io_ctx->sockindex,
+ (void *)buf, buflen, &nwrote);
if(result == CURLE_AGAIN) {
DEBUGF(infof(data, "Curl_hyper_send(%zu) -> EAGAIN", buflen));
/* would block, register interest */
may be parts of the request that is not yet sent, since we can deal with
the rest of the request in the PERFORM phase. */
*done = TRUE;
- Curl_client_cleanup(data);
+ Curl_cw_reset(data);
/* Add collecting of headers written to client. For a new connection,
* we might have done that already, but reuse
goto error;
}
/* tell Hyper how to read/write network data */
- hyper_io_set_userdata(io, data);
+ h->io_ctx.data = data;
+ h->io_ctx.sockindex = FIRSTSOCKET;
+ hyper_io_set_userdata(io, &h->io_ctx);
hyper_io_set_read(io, Curl_hyper_recv);
hyper_io_set_write(io, Curl_hyper_send);
if((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) {
/* HTTP GET/HEAD download */
Curl_pgrsSetUploadSize(data, 0); /* nothing */
- Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, -1);
+ Curl_xfer_setup(data, FIRSTSOCKET, -1, TRUE, -1);
}
conn->datastream = Curl_hyper_stream;
if(data->state.expect100header)
#include <hyper.h>
+struct hyp_io_ctx {
+ struct Curl_easy *data;
+ int sockindex;
+};
+
/* per-transfer data for the Hyper backend */
struct hyptransfer {
hyper_waker *write_waker;
const hyper_executor *exec;
hyper_waker *exp100_waker;
hyper_waker *send_body_waker;
+ struct hyp_io_ctx io_ctx;
};
size_t Curl_hyper_recv(void *userp, hyper_context *ctx,
{
CURLcode result = CURLE_OK;
struct SingleRequest *k = &data->req;
- curl_socket_t tunnelsocket = Curl_conn_cf_get_socket(cf, data);
char *linep;
size_t line_len;
int error, writetype;
/* Read one byte at a time to avoid a race condition. Wait at most one
second before looping to ensure continuous pgrsUpdates. */
- result = Curl_read(data, tunnelsocket, &byte, 1, &nread);
+ result = Curl_conn_recv(data, cf->sockindex, &byte, 1, &nread);
if(result == CURLE_AGAIN)
/* socket buffer drained, return */
return CURLE_OK;
goto error;
}
/* tell Hyper how to read/write network data */
- hyper_io_set_userdata(io, data);
+ h->io_ctx.data = data;
+ h->io_ctx.sockindex = cf->sockindex;
+ hyper_io_set_userdata(io, &h->io_ctx);
hyper_io_set_read(io, Curl_hyper_recv);
hyper_io_set_write(io, Curl_hyper_send);
conn->sockfd = tunnelsocket;
data->req.header = TRUE; /* assume header */
data->req.bytecount = 0;
data->req.ignorebody = FALSE;
- Curl_client_cleanup(data);
+ Curl_cw_reset(data);
Curl_pgrsSetUploadCounter(data, 0);
Curl_pgrsSetDownloadCounter(data, 0);
case HAPROXY_SEND:
len = Curl_dyn_len(&ctx->data_out);
if(len > 0) {
- ssize_t written = Curl_conn_send(data, cf->sockindex,
- Curl_dyn_ptr(&ctx->data_out),
- len, &result);
- if(written < 0)
+ ssize_t written;
+ result = Curl_conn_send(data, cf->sockindex,
+ Curl_dyn_ptr(&ctx->data_out),
+ len, &written);
+ if(result == CURLE_AGAIN) {
+ result = CURLE_OK;
+ written = 0;
+ }
+ else if(result)
goto out;
+ DEBUGASSERT(written >= 0);
Curl_dyn_tail(&ctx->data_out, len - (size_t)written);
if(Curl_dyn_len(&ctx->data_out) > 0) {
result = CURLE_OK;
}
}
-ssize_t Curl_conn_recv(struct Curl_easy *data, int num, char *buf,
- size_t len, CURLcode *code)
+ssize_t Curl_cf_recv(struct Curl_easy *data, int num, char *buf,
+ size_t len, CURLcode *code)
{
struct Curl_cfilter *cf;
DEBUGASSERT(data);
DEBUGASSERT(data->conn);
+ *code = CURLE_OK;
cf = data->conn->cfilter[num];
while(cf && !cf->connected) {
cf = cf->next;
}
if(cf) {
- return cf->cft->do_recv(cf, data, buf, len, code);
+ ssize_t nread = cf->cft->do_recv(cf, data, buf, len, code);
+ DEBUGASSERT(nread >= 0 || *code);
+ DEBUGASSERT(nread < 0 || !*code);
+ return nread;
}
failf(data, "recv: no filter connected");
*code = CURLE_FAILED_INIT;
return -1;
}
-ssize_t Curl_conn_send(struct Curl_easy *data, int num,
- const void *mem, size_t len, CURLcode *code)
+ssize_t Curl_cf_send(struct Curl_easy *data, int num,
+ const void *mem, size_t len, CURLcode *code)
{
struct Curl_cfilter *cf;
DEBUGASSERT(data);
DEBUGASSERT(data->conn);
+ *code = CURLE_OK;
cf = data->conn->cfilter[num];
while(cf && !cf->connected) {
cf = cf->next;
}
if(cf) {
- return cf->cft->do_send(cf, data, mem, len, code);
+ ssize_t nwritten = cf->cft->do_send(cf, data, mem, len, code);
+ DEBUGASSERT(nwritten >= 0 || *code);
+ DEBUGASSERT(nwritten < 0 || !*code || !len);
+ return nwritten;
}
failf(data, "send: no filter connected");
DEBUGASSERT(0);
return (result || n <= 0)? 1 : (size_t)n;
}
+int Curl_conn_sockindex(struct Curl_easy *data, curl_socket_t sockfd)
+{
+ if(data && data->conn &&
+ sockfd != CURL_SOCKET_BAD && sockfd == data->conn->sock[SECONDARYSOCKET])
+ return SECONDARYSOCKET;
+ return FIRSTSOCKET;
+}
+
+CURLcode Curl_conn_recv(struct Curl_easy *data, int sockindex,
+ char *buf, size_t blen, ssize_t *n)
+{
+ CURLcode result = CURLE_OK;
+ ssize_t nread;
+
+ DEBUGASSERT(data->conn);
+ nread = data->conn->recv[sockindex](data, sockindex, buf, blen, &result);
+ DEBUGASSERT(nread >= 0 || result);
+ DEBUGASSERT(nread < 0 || !result);
+ *n = (nread >= 0)? (size_t)nread : 0;
+ return result;
+}
+
+CURLcode Curl_conn_send(struct Curl_easy *data, int sockindex,
+ const void *buf, size_t blen,
+ ssize_t *pnwritten)
+{
+ ssize_t nwritten;
+ CURLcode result = CURLE_OK;
+ struct connectdata *conn;
+
+ DEBUGASSERT(sockindex >= 0 && sockindex < 2);
+ DEBUGASSERT(pnwritten);
+ DEBUGASSERT(data);
+ DEBUGASSERT(data->conn);
+ conn = data->conn;
+#ifdef CURLDEBUG
+ {
+ /* Allow debug builds to override this logic to force short sends
+ */
+ char *p = getenv("CURL_SMALLSENDS");
+ if(p) {
+ size_t altsize = (size_t)strtoul(p, NULL, 10);
+ if(altsize)
+ blen = CURLMIN(blen, altsize);
+ }
+ }
+#endif
+ nwritten = conn->send[sockindex](data, sockindex, buf, blen, &result);
+ DEBUGASSERT((nwritten >= 0) || result);
+ *pnwritten = nwritten;
+ return result;
+}
void Curl_pollset_reset(struct Curl_easy *data,
struct easy_pollset *ps)
* actuel number of bytes copied or a negative value on error.
* The error code is placed into `*code`.
*/
-ssize_t Curl_conn_recv(struct Curl_easy *data, int sockindex, char *buf,
- size_t len, CURLcode *code);
+ssize_t Curl_cf_recv(struct Curl_easy *data, int sockindex, char *buf,
+ size_t len, CURLcode *code);
/**
* Send `len` bytes of data from `buf` through the filter chain `sockindex`
* or a negative value on error.
* The error code is placed into `*code`.
*/
-ssize_t Curl_conn_send(struct Curl_easy *data, int sockindex,
- const void *buf, size_t len, CURLcode *code);
+ssize_t Curl_cf_send(struct Curl_easy *data, int sockindex,
+ const void *buf, size_t len, CURLcode *code);
/**
* The easy handle `data` is being attached to `conn`. This does
int sockindex);
+/**
+ * Get the index of the given socket in the connection's sockets.
+ * Useful in calling `Curl_conn_send()/Curl_conn_recv()` with the
+ * correct socket index.
+ */
+int Curl_conn_sockindex(struct Curl_easy *data, curl_socket_t sockfd);
+
+/*
+ * Receive data on the connection, using FIRSTSOCKET/SECONDARYSOCKET.
+ * Will return CURLE_AGAIN iff blocked on receiving.
+ */
+CURLcode Curl_conn_recv(struct Curl_easy *data, int sockindex,
+ char *buf, size_t buffersize,
+ ssize_t *pnread);
+
+/*
+ * Send data on the connection, using FIRSTSOCKET/SECONDARYSOCKET.
+ * Will return CURLE_AGAIN iff blocked on sending.
+ */
+CURLcode Curl_conn_send(struct Curl_easy *data, int sockindex,
+ const void *buf, size_t blen,
+ ssize_t *pnwritten);
+
+
void Curl_pollset_reset(struct Curl_easy *data,
struct easy_pollset *ps);
if(data->state.upload) {
Curl_pgrsSetUploadSize(data, data->state.infilesize);
- Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
+ Curl_xfer_setup(data, -1, -1, FALSE, FIRSTSOCKET);
}
else
- Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
+ Curl_xfer_setup(data, FIRSTSOCKET, -1, FALSE, -1);
*done = TRUE;
return CURLE_OK;
}
}
/* sendf() sends formatted data to the server */
-static CURLcode sendf(curl_socket_t sockfd, struct Curl_easy *data,
- const char *fmt, ...) CURL_PRINTF(3, 4);
+static CURLcode sendf(struct Curl_easy *data,
+ const char *fmt, ...) CURL_PRINTF(2, 3);
-static CURLcode sendf(curl_socket_t sockfd, struct Curl_easy *data,
- const char *fmt, ...)
+static CURLcode sendf(struct Curl_easy *data, const char *fmt, ...)
{
ssize_t bytes_written;
size_t write_len;
for(;;) {
/* Write the buffer to the socket */
- result = Curl_write(data, sockfd, sptr, write_len, &bytes_written);
+ result = Curl_xfer_send(data, sptr, write_len, &bytes_written);
if(result)
break;
char *nthdef = NULL; /* This is not part of the protocol, but required
by RFC 2229 */
CURLcode result;
- struct connectdata *conn = data->conn;
- curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
char *path;
goto error;
}
- result = sendf(sockfd, data,
+ result = sendf(data,
"CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
"MATCH "
"%s " /* database */
failf(data, "Failed sending DICT request");
goto error;
}
- Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1); /* no upload */
+ Curl_xfer_setup(data, FIRSTSOCKET, -1, FALSE, -1); /* no upload */
}
else if(strncasecompare(path, DICT_DEFINE, sizeof(DICT_DEFINE)-1) ||
strncasecompare(path, DICT_DEFINE2, sizeof(DICT_DEFINE2)-1) ||
goto error;
}
- result = sendf(sockfd, data,
+ result = sendf(data,
"CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
"DEFINE "
"%s " /* database */
failf(data, "Failed sending DICT request");
goto error;
}
- Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
+ Curl_xfer_setup(data, FIRSTSOCKET, -1, FALSE, -1);
}
else {
if(ppath[i] == ':')
ppath[i] = ' ';
}
- result = sendf(sockfd, data,
+ result = sendf(data,
"CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
"%s\r\n"
"QUIT\r\n", ppath);
goto error;
}
- Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
+ Curl_xfer_setup(data, FIRSTSOCKET, -1, FALSE, -1);
}
}
*/
void curl_easy_reset(struct Curl_easy *data)
{
- Curl_free_request_state(data);
+ Curl_req_reset(&data->req, data);
/* zero out UserDefined data: */
Curl_freeset(data);
}
-static CURLcode easy_connection(struct Curl_easy *data, curl_socket_t *sfd,
+static CURLcode easy_connection(struct Curl_easy *data,
struct connectdata **connp)
{
+ curl_socket_t sfd;
+
if(!data)
return CURLE_BAD_FUNCTION_ARGUMENT;
return CURLE_UNSUPPORTED_PROTOCOL;
}
- *sfd = Curl_getconnectinfo(data, connp);
+ sfd = Curl_getconnectinfo(data, connp);
- if(*sfd == CURL_SOCKET_BAD) {
+ if(sfd == CURL_SOCKET_BAD) {
failf(data, "Failed to get recent socket");
return CURLE_UNSUPPORTED_PROTOCOL;
}
CURLcode curl_easy_recv(struct Curl_easy *data, void *buffer, size_t buflen,
size_t *n)
{
- curl_socket_t sfd;
CURLcode result;
ssize_t n1;
struct connectdata *c;
if(Curl_is_in_callback(data))
return CURLE_RECURSIVE_API_CALL;
- result = easy_connection(data, &sfd, &c);
+ result = easy_connection(data, &c);
if(result)
return result;
Curl_attach_connection(data, c);
*n = 0;
- result = Curl_read(data, sfd, buffer, buflen, &n1);
+ result = Curl_conn_recv(data, FIRSTSOCKET, buffer, buflen, &n1);
if(result)
return result;
#ifdef USE_WEBSOCKETS
CURLcode Curl_connect_only_attach(struct Curl_easy *data)
{
- curl_socket_t sfd;
CURLcode result;
struct connectdata *c = NULL;
- result = easy_connection(data, &sfd, &c);
+ result = easy_connection(data, &c);
if(result)
return result;
CURLcode Curl_senddata(struct Curl_easy *data, const void *buffer,
size_t buflen, ssize_t *n)
{
- curl_socket_t sfd;
CURLcode result;
- ssize_t n1;
struct connectdata *c = NULL;
SIGPIPE_VARIABLE(pipe_st);
- result = easy_connection(data, &sfd, &c);
+ *n = 0;
+ result = easy_connection(data, &c);
if(result)
return result;
needs to be reattached */
Curl_attach_connection(data, c);
- *n = 0;
sigpipe_ignore(data, &pipe_st);
- result = Curl_write(data, sfd, buffer, buflen, &n1);
+ result = Curl_conn_send(data, FIRSTSOCKET, buffer, buflen, n);
sigpipe_restore(&pipe_st);
- if(n1 == -1)
+ if(result && result != CURLE_AGAIN)
return CURLE_SEND_ERROR;
-
- /* detect EAGAIN */
- if(!result && !n1)
- return CURLE_AGAIN;
-
- *n = n1;
-
return result;
}
static void wc_data_dtor(void *ptr);
static CURLcode ftp_state_retr(struct Curl_easy *data, curl_off_t filesize);
static CURLcode ftp_readresp(struct Curl_easy *data,
- curl_socket_t sockfd,
+ int sockindex,
struct pingpong *pp,
int *ftpcode,
size_t *size);
/* set the SO_SNDBUF for the secondary socket for those who need it */
Curl_sndbufset(conn->sock[SECONDARYSOCKET]);
- Curl_setup_transfer(data, -1, -1, FALSE, SECONDARYSOCKET);
+ Curl_xfer_setup(data, -1, -1, FALSE, SECONDARYSOCKET);
}
else {
/* FTP download: */
- Curl_setup_transfer(data, SECONDARYSOCKET,
- conn->proto.ftpc.retr_size_saved, FALSE, -1);
+ Curl_xfer_setup(data, SECONDARYSOCKET,
+ conn->proto.ftpc.retr_size_saved, FALSE, -1);
}
conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */
}
static CURLcode ftp_readresp(struct Curl_easy *data,
- curl_socket_t sockfd,
+ int sockindex,
struct pingpong *pp,
int *ftpcode, /* return the ftp-code if done */
size_t *size) /* size of the response */
{
int code;
- CURLcode result = Curl_pp_readresp(data, sockfd, pp, &code, size);
+ CURLcode result = Curl_pp_readresp(data, sockindex, pp, &code, size);
#ifdef HAVE_GSSAPI
{
break;
}
}
- result = ftp_readresp(data, sockfd, pp, ftpcode, &nread);
+ result = ftp_readresp(data, FIRSTSOCKET, pp, ftpcode, &nread);
if(result)
break;
infof(data, "File already completely uploaded");
/* no data to transfer */
- Curl_setup_transfer(data, -1, -1, FALSE, -1);
+ Curl_xfer_setup(data, -1, -1, FALSE, -1);
/* Set ->transfer so that we won't get any error in
* ftp_done() because we didn't transfer anything! */
if(ftp->downloadsize == 0) {
/* no data to transfer */
- Curl_setup_transfer(data, -1, -1, FALSE, -1);
+ Curl_xfer_setup(data, -1, -1, FALSE, -1);
infof(data, "File already completely downloaded");
/* Set ->transfer so that we won't get any error in ftp_done()
struct connectdata *conn)
{
CURLcode result;
- curl_socket_t sock = conn->sock[FIRSTSOCKET];
int ftpcode;
struct ftp_conn *ftpc = &conn->proto.ftpc;
struct pingpong *pp = &ftpc->pp;
if(pp->sendleft)
return Curl_pp_flushsend(data, pp);
- result = ftp_readresp(data, sock, pp, &ftpcode, &nread);
+ result = ftp_readresp(data, FIRSTSOCKET, pp, &ftpcode, &nread);
if(result)
return result;
}
/* no data to transfer */
- Curl_setup_transfer(data, -1, -1, FALSE, -1);
+ Curl_xfer_setup(data, -1, -1, FALSE, -1);
if(!ftpc->wait_data_conn) {
/* no waiting for the data connection so this is now complete */
if(ftp->transfer != PPTRANSFER_BODY)
/* no data to transfer */
- Curl_setup_transfer(data, -1, -1, FALSE, -1);
+ Curl_xfer_setup(data, -1, -1, FALSE, -1);
else if(!connected)
/* since we didn't connect now, we want do_more to get called */
conn->bits.do_more = TRUE;
if(strlen(sel) < 1)
break;
- result = Curl_nwrite(data, FIRSTSOCKET, sel, k, &amount);
+ result = Curl_xfer_send(data, sel, k, &amount);
if(!result) { /* Which may not have written it all! */
result = Curl_client_write(data, CLIENTWRITE_HEADER, sel, amount);
if(result)
free(sel_org);
if(!result)
- result = Curl_nwrite(data, FIRSTSOCKET, "\r\n", 2, &amount);
+ result = Curl_xfer_send(data, "\r\n", 2, &amount);
if(result) {
failf(data, "Failed sending Gopher request");
return result;
if(result)
return result;
- Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
+ Curl_xfer_setup(data, FIRSTSOCKET, -1, FALSE, -1);
return CURLE_OK;
}
#endif /* CURL_DISABLE_GOPHER */
sendsize = (size_t)data->set.upload_buffer_size;
}
- result = Curl_nwrite(data, sockindex, ptr, sendsize, &amount);
+ result = Curl_conn_send(data, sockindex, ptr, sendsize, &amount);
+ if(result == CURLE_AGAIN) {
+ result = CURLE_OK;
+ amount = 0;
+ }
if(!result) {
/*
failf(data, "Failed sending PUT request");
else
/* prepare for transfer */
- Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE,
- http->postsize?FIRSTSOCKET:-1);
+ Curl_xfer_setup(data, FIRSTSOCKET, -1, TRUE,
+ http->postsize?FIRSTSOCKET:-1);
if(result)
return result;
break;
failf(data, "Failed sending POST request");
else
/* setup variables for the upcoming transfer */
- Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, -1);
+ Curl_xfer_setup(data, FIRSTSOCKET, -1, TRUE, -1);
break;
}
failf(data, "Failed sending POST request");
else
/* prepare for transfer */
- Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE,
- http->postsize?FIRSTSOCKET:-1);
+ Curl_xfer_setup(data, FIRSTSOCKET, -1, TRUE,
+ http->postsize?FIRSTSOCKET:-1);
if(result)
return result;
if(result)
failf(data, "Failed sending HTTP POST request");
else
- Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE,
- http->postdata?FIRSTSOCKET:-1);
+ Curl_xfer_setup(data, FIRSTSOCKET, -1, TRUE,
+ http->postdata?FIRSTSOCKET:-1);
break;
default:
!(data->set.connect_only))
/* Set up the transfer for two-way since without CONNECT_ONLY set, this
request probably wants to send data too post upgrade */
- Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, FIRSTSOCKET);
+ Curl_xfer_setup(data, FIRSTSOCKET, -1, TRUE, FIRSTSOCKET);
#endif
else
/* HTTP GET/HEAD download: */
- Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, -1);
+ Curl_xfer_setup(data, FIRSTSOCKET, -1, TRUE, -1);
}
return result;
if(data->req.bytecount == size)
/* The entire data is already transferred! */
- Curl_setup_transfer(data, -1, -1, FALSE, -1);
+ Curl_xfer_setup(data, -1, -1, FALSE, -1);
else {
/* IMAP download */
data->req.maxdownload = size;
/* force a recv/send check of this connection, as the data might've been
read off the socket already */
data->state.select_bits = CURL_CSELECT_IN;
- Curl_setup_transfer(data, FIRSTSOCKET, size, FALSE, -1);
+ Curl_xfer_setup(data, FIRSTSOCKET, size, FALSE, -1);
}
}
else {
Curl_pgrsSetUploadSize(data, data->state.infilesize);
/* IMAP upload */
- Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
+ Curl_xfer_setup(data, -1, -1, FALSE, FIRSTSOCKET);
/* End of DO phase */
imap_state(data, IMAP_STOP);
struct connectdata *conn)
{
CURLcode result = CURLE_OK;
- curl_socket_t sock = conn->sock[FIRSTSOCKET];
int imapcode;
struct imap_conn *imapc = &conn->proto.imapc;
struct pingpong *pp = &imapc->pp;
do {
/* Read the response from the server */
- result = Curl_pp_readresp(data, sock, pp, &imapcode, &nread);
+ result = Curl_pp_readresp(data, FIRSTSOCKET, pp, &imapcode, &nread);
if(result)
return result;
if(imap->transfer != PPTRANSFER_BODY)
/* no data to transfer */
- Curl_setup_transfer(data, -1, -1, FALSE, -1);
+ Curl_xfer_setup(data, -1, -1, FALSE, -1);
return CURLE_OK;
}
#include "ftp.h"
#include "curl_gssapi.h"
#include "sendf.h"
+#include "transfer.h"
#include "curl_krb5.h"
#include "warnless.h"
#include "strcase.h"
#ifdef HAVE_GSSAPI
conn->data_prot = PROT_CMD;
#endif
- result = Curl_nwrite(data, FIRSTSOCKET, sptr, write_len,
- &bytes_written);
+ result = Curl_xfer_send(data, sptr, write_len, &bytes_written);
#ifdef HAVE_GSSAPI
DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST);
conn->data_prot = data_sec;
ssize_t nread = 0;
while(len > 0) {
- nread = Curl_conn_recv(data, sockindex, to_p, len, &result);
+ result = Curl_conn_recv(data, sockindex, to_p, len, &nread);
if(nread > 0) {
len -= nread;
to_p += nread;
ssize_t written;
while(len > 0) {
- written = Curl_conn_send(data, sockindex, to_p, len, &result);
- if(written > 0) {
+ result = Curl_conn_send(data, sockindex, to_p, len, &written);
+ if(!result && written > 0) {
len -= written;
to_p += written;
}
*err = CURLE_OK;
/* Handle clear text response. */
- if(conn->sec_complete == 0 || conn->data_prot == PROT_CLEAR)
- return Curl_conn_recv(data, sockindex, buffer, len, err);
+ if(conn->sec_complete == 0 || conn->data_prot == PROT_CLEAR) {
+ ssize_t nread;
+ *err = Curl_conn_recv(data, sockindex, buffer, len, &nread);
+ return nread;
+ }
if(conn->in_buffer.eof_flag) {
conn->in_buffer.eof_flag = 0;
FREE_ON_WINLDAP(host);
/* no data to transfer */
- Curl_setup_transfer(data, -1, -1, FALSE, -1);
+ Curl_xfer_setup(data, -1, -1, FALSE, -1);
connclose(conn, "LDAP connection always disable reuse");
return result;
CURLcode result = CURLE_OK;
struct MQTT *mq = data->req.p.mqtt;
ssize_t n;
- result = Curl_nwrite(data, FIRSTSOCKET, buf, len, &n);
+ result = Curl_xfer_send(data, buf, len, &n);
if(result)
return result;
Curl_debug(data, CURLINFO_HEADER_OUT, buf, (size_t)n);
ssize_t nread;
DEBUGASSERT(nbytes - rlen < sizeof(readbuf));
- result = Curl_read(data, data->conn->sock[FIRSTSOCKET],
- (char *)readbuf, nbytes - rlen, &nread);
+ result = Curl_xfer_recv(data, (char *)readbuf, nbytes - rlen, &nread);
if(result)
return result;
DEBUGASSERT(nread >= 0);
{
CURLcode result = CURLE_OK;
struct connectdata *conn = data->conn;
- curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
ssize_t nread;
size_t remlen;
struct mqtt_conn *mqtt = &conn->proto.mqtt;
size_t rest = mq->npacket;
if(rest > sizeof(buffer))
rest = sizeof(buffer);
- result = Curl_read(data, sockfd, buffer, rest, &nread);
+ result = Curl_xfer_recv(data, buffer, rest, &nread);
if(result) {
if(CURLE_AGAIN == result) {
infof(data, "EEEE AAAAGAIN");
struct mqtt_conn *mqtt = &conn->proto.mqtt;
struct MQTT *mq = data->req.p.mqtt;
ssize_t nread;
- curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
unsigned char byte;
*done = FALSE;
switch(mqtt->state) {
case MQTT_FIRST:
/* Read the initial byte only */
- result = Curl_read(data, sockfd, (char *)&mq->firstbyte, 1, &nread);
+ result = Curl_xfer_recv(data, (char *)&mq->firstbyte, 1, &nread);
if(result)
break;
else if(!nread) {
FALLTHROUGH();
case MQTT_REMAINING_LENGTH:
do {
- result = Curl_read(data, sockfd, (char *)&byte, 1, &nread);
+ result = Curl_xfer_recv(data, (char *)&byte, 1, &nread);
if(!nread)
break;
Curl_debug(data, CURLINFO_HEADER_IN, (char *)&byte, 1);
process_pending_handles(data->multi); /* connection / multiplex */
- Curl_safefree(data->state.ulbuf);
+ if(!result)
+ result = Curl_req_done(&data->req, data, premature);
- Curl_client_cleanup(data);
+ Curl_safefree(data->state.ulbuf);
CONNCACHE_LOCK(data);
Curl_detach_connection(data);
{
struct connectdata *conn = data->conn;
(void)socks;
- /* Not using `conn->sockfd` as `Curl_setup_transfer()` initializes
+ /* Not using `conn->sockfd` as `Curl_xfer_setup()` initializes
* that *after* the connect. */
if(conn && conn->sock[FIRSTSOCKET] != CURL_SOCKET_BAD) {
/* Default is to wait to something from the server */
else {
lr->msgid = msgid;
data->req.p.ldap = lr;
- Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
+ Curl_xfer_setup(data, FIRSTSOCKET, -1, FALSE, -1);
*done = TRUE;
}
}
#ifdef HAVE_GSSAPI
conn->data_prot = PROT_CMD;
#endif
- result = Curl_nwrite(data, FIRSTSOCKET, s, write_len, &bytes_written);
- if(result)
+ result = Curl_conn_send(data, FIRSTSOCKET, s, write_len, &bytes_written);
+ if(result == CURLE_AGAIN) {
+ bytes_written = 0;
+ }
+ else if(result)
return result;
#ifdef HAVE_GSSAPI
data_sec = conn->data_prot;
}
static CURLcode pingpong_read(struct Curl_easy *data,
- curl_socket_t sockfd,
+ int sockindex,
char *buffer,
size_t buflen,
ssize_t *nread)
enum protection_level prot = data->conn->data_prot;
data->conn->data_prot = PROT_CLEAR;
#endif
- result = Curl_read(data, sockfd, buffer, buflen, nread);
+ result = Curl_conn_recv(data, sockindex, buffer, buflen, nread);
#ifdef HAVE_GSSAPI
DEBUGASSERT(prot > PROT_NONE && prot < PROT_LAST);
data->conn->data_prot = (unsigned char)prot;
* Reads a piece of a server response.
*/
CURLcode Curl_pp_readresp(struct Curl_easy *data,
- curl_socket_t sockfd,
+ int sockindex,
struct pingpong *pp,
int *code, /* return the server code if done */
size_t *size) /* size of the response */
ssize_t gotbytes = 0;
char buffer[900];
- result = pingpong_read(data, sockfd, buffer, sizeof(buffer), &gotbytes);
+ result = pingpong_read(data, sockindex, buffer, sizeof(buffer), &gotbytes);
if(result == CURLE_AGAIN)
return CURLE_OK;
{
/* we have a piece of a command still left to send */
ssize_t written;
- CURLcode result = Curl_nwrite(data, FIRSTSOCKET,
- pp->sendthis + pp->sendsize - pp->sendleft,
- pp->sendleft, &written);
+ CURLcode result;
+
+ result = Curl_conn_send(data, FIRSTSOCKET,
+ pp->sendthis + pp->sendsize - pp->sendleft,
+ pp->sendleft, &written);
+ if(result == CURLE_AGAIN) {
+ result = CURLE_OK;
+ written = 0;
+ }
if(result)
return result;
* Reads a piece of a server response.
*/
CURLcode Curl_pp_readresp(struct Curl_easy *data,
- curl_socket_t sockfd,
+ int sockindex,
struct pingpong *pp,
int *code, /* return the server code if done */
size_t *size); /* size of the response */
if(pop3->transfer == PPTRANSFER_BODY) {
/* POP3 download */
- Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
+ Curl_xfer_setup(data, FIRSTSOCKET, -1, FALSE, -1);
if(pp->overflow) {
/* The recv buffer contains data that is actually body content so send
struct connectdata *conn)
{
CURLcode result = CURLE_OK;
- curl_socket_t sock = conn->sock[FIRSTSOCKET];
int pop3code;
struct pop3_conn *pop3c = &conn->proto.pop3c;
struct pingpong *pp = &pop3c->pp;
do {
/* Read the response from the server */
- result = Curl_pp_readresp(data, sock, pp, &pop3code, &nread);
+ result = Curl_pp_readresp(data, FIRSTSOCKET, pp, &pop3code, &nread);
if(result)
return result;
--- /dev/null
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include "urldata.h"
+#include "dynbuf.h"
+#include "doh.h"
+#include "request.h"
+#include "sendf.h"
+#include "url.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+CURLcode Curl_req_init(struct SingleRequest *req)
+{
+ memset(req, 0, sizeof(*req));
+ Curl_bufq_init2(&req->sendbuf, UPLOADBUFFER_DEFAULT, 1,
+ BUFQ_OPT_SOFT_LIMIT);
+ return CURLE_OK;
+}
+
+CURLcode Curl_req_start(struct SingleRequest *req,
+ struct Curl_easy *data)
+{
+ req->start = Curl_now();
+ Curl_cw_reset(data);
+ return CURLE_OK;
+}
+
+CURLcode Curl_req_done(struct SingleRequest *req,
+ struct Curl_easy *data, bool aborted)
+{
+ (void)req;
+ /* TODO: add flush handling for client output */
+ (void)aborted;
+ Curl_cw_reset(data);
+ return CURLE_OK;
+}
+
+void Curl_req_reset(struct SingleRequest *req, struct Curl_easy *data)
+{
+ /* This is a bit ugly. `req->p` is a union and we assume we can
+ * free this safely without leaks. */
+ Curl_safefree(req->p.http);
+ Curl_safefree(req->newurl);
+ Curl_cw_reset(data);
+
+ Curl_bufq_reset(&req->sendbuf);
+ if(data->set.upload_buffer_size != req->sendbuf.chunk_size) {
+ Curl_bufq_free(&req->sendbuf);
+ Curl_bufq_init2(&req->sendbuf, data->set.upload_buffer_size, 1,
+ BUFQ_OPT_SOFT_LIMIT);
+ }
+
+#ifndef CURL_DISABLE_DOH
+ if(req->doh) {
+ Curl_close(&req->doh->probe[0].easy);
+ Curl_close(&req->doh->probe[1].easy);
+ }
+#endif
+}
+
+void Curl_req_free(struct SingleRequest *req, struct Curl_easy *data)
+{
+ /* This is a bit ugly. `req->p` is a union and we assume we can
+ * free this safely without leaks. */
+ Curl_safefree(req->p.http);
+ Curl_safefree(req->newurl);
+ Curl_bufq_free(&req->sendbuf);
+ Curl_cw_reset(data);
+
+#ifndef CURL_DISABLE_DOH
+ if(req->doh) {
+ Curl_close(&req->doh->probe[0].easy);
+ Curl_close(&req->doh->probe[1].easy);
+ Curl_dyn_free(&req->doh->probe[0].serverdoh);
+ Curl_dyn_free(&req->doh->probe[1].serverdoh);
+ curl_slist_free_all(req->doh->headers);
+ Curl_safefree(req->doh);
+ }
+#endif
+}
+
--- /dev/null
+#ifndef HEADER_CURL_REQUEST_H
+#define HEADER_CURL_REQUEST_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/* This file is for lib internal stuff */
+
+#include "curl_setup.h"
+
+#include "bufq.h"
+
+/* forward declarations */
+struct UserDefined;
+
+enum expect100 {
+ EXP100_SEND_DATA, /* enough waiting, just send the body now */
+ EXP100_AWAITING_CONTINUE, /* waiting for the 100 Continue header */
+ EXP100_SENDING_REQUEST, /* still sending the request but will wait for
+ the 100 header once done with the request */
+ EXP100_FAILED /* used on 417 Expectation Failed */
+};
+
+enum upgrade101 {
+ UPGR101_INIT, /* default state */
+ UPGR101_WS, /* upgrade to WebSockets requested */
+ UPGR101_H2, /* upgrade to HTTP/2 requested */
+ UPGR101_RECEIVED, /* 101 response received */
+ UPGR101_WORKING /* talking upgraded protocol */
+};
+
+
+/*
+ * Request specific data in the easy handle (Curl_easy). Previously,
+ * these members were on the connectdata struct but since a conn struct may
+ * now be shared between different Curl_easys, we store connection-specific
+ * data here. This struct only keeps stuff that's interesting for *this*
+ * request, as it will be cleared between multiple ones
+ */
+struct SingleRequest {
+ curl_off_t size; /* -1 if unknown at this point */
+ curl_off_t maxdownload; /* in bytes, the maximum amount of data to fetch,
+ -1 means unlimited */
+ curl_off_t bytecount; /* total number of bytes read */
+ curl_off_t writebytecount; /* number of bytes written */
+
+ curl_off_t pendingheader; /* this many bytes left to send is actually
+ header and not body */
+ struct curltime start; /* transfer started at this time */
+ unsigned int headerbytecount; /* received server headers (not CONNECT
+ headers) */
+ unsigned int allheadercount; /* all received headers (server + CONNECT) */
+ unsigned int deductheadercount; /* this amount of bytes doesn't count when
+ we check if anything has been transferred
+ at the end of a connection. We use this
+ counter to make only a 100 reply (without
+ a following second response code) result
+ in a CURLE_GOT_NOTHING error code */
+ int headerline; /* counts header lines to better track the
+ first one */
+ curl_off_t offset; /* possible resume offset read from the
+ Content-Range: header */
+ int httpcode; /* error code from the 'HTTP/1.? XXX' or
+ 'RTSP/1.? XXX' line */
+ int keepon;
+ struct curltime start100; /* time stamp to wait for the 100 code from */
+ enum expect100 exp100; /* expect 100 continue state */
+ enum upgrade101 upgr101; /* 101 upgrade state */
+
+ /* Client Writer stack, handles trasnfer- and content-encodings, protocol
+ * checks, pausing by client callbacks. */
+ struct Curl_cwriter *writer_stack;
+ struct bufq sendbuf; /* data which needs to be send to the server */
+ time_t timeofdoc;
+ long bodywrites;
+ char *location; /* This points to an allocated version of the Location:
+ header data */
+ char *newurl; /* Set to the new URL to use when a redirect or a retry is
+ wanted */
+
+ /* 'upload_present' is used to keep a byte counter of how much data there is
+ still left in the buffer, aimed for upload. */
+ ssize_t upload_present;
+
+ /* 'upload_fromhere' is used as a read-pointer when we uploaded parts of a
+ buffer, so the next read should read from where this pointer points to,
+ and the 'upload_present' contains the number of bytes available at this
+ position */
+ char *upload_fromhere;
+
+ /* Allocated protocol-specific data. Each protocol handler makes sure this
+ points to data it needs. */
+ union {
+ struct FILEPROTO *file;
+ struct FTP *ftp;
+ struct HTTP *http;
+ struct IMAP *imap;
+ struct ldapreqinfo *ldap;
+ struct MQTT *mqtt;
+ struct POP3 *pop3;
+ struct RTSP *rtsp;
+ struct smb_request *smb;
+ struct SMTP *smtp;
+ struct SSHPROTO *ssh;
+ struct TELNET *telnet;
+ } p;
+#ifndef CURL_DISABLE_DOH
+ struct dohdata *doh; /* DoH specific data for this request */
+#endif
+ char fread_eof[2]; /* the body read callback (index 0) returned EOF or
+ the trailer read callback (index 1) returned EOF */
+#ifndef CURL_DISABLE_COOKIES
+ unsigned char setcookies;
+#endif
+ BIT(header); /* incoming data has HTTP header */
+ BIT(content_range); /* set TRUE if Content-Range: was found */
+ BIT(download_done); /* set to TRUE when download is complete */
+ BIT(eos_written); /* iff EOS has been written to client */
+ BIT(upload_done); /* set to TRUE when doing chunked transfer-encoding
+ upload and we're uploading the last chunk */
+ BIT(ignorebody); /* we read a response-body but we ignore it! */
+ BIT(http_bodyless); /* HTTP response status code is between 100 and 199,
+ 204 or 304 */
+ BIT(chunk); /* if set, this is a chunked transfer-encoding */
+ BIT(ignore_cl); /* ignore content-length */
+ BIT(upload_chunky); /* set TRUE if we are doing chunked transfer-encoding
+ on upload */
+ BIT(getheader); /* TRUE if header parsing is wanted */
+ BIT(forbidchunk); /* used only to explicitly forbid chunk-upload for
+ specific upload buffers. See readmoredata() in http.c
+ for details. */
+ BIT(no_body); /* the response has no body */
+ BIT(authneg); /* TRUE when the auth phase has started, which means
+ that we are creating a request with an auth header,
+ but it is not the final request in the auth
+ negotiation. */
+};
+
+/**
+ * Initialize the state of the request for first use.
+ */
+CURLcode Curl_req_init(struct SingleRequest *req);
+
+/**
+ * The request is about to start.
+ */
+CURLcode Curl_req_start(struct SingleRequest *req,
+ struct Curl_easy *data);
+
+/**
+ * The request is done. If not aborted, make sure that buffers are
+ * flushed to the client.
+ * @param req the request
+ * @param data the transfer
+ * @param aborted TRUE iff the request was aborted/errored
+ */
+CURLcode Curl_req_done(struct SingleRequest *req,
+ struct Curl_easy *data, bool aborted);
+
+/**
+ * Free the state of the request, not usable afterwards.
+ */
+void Curl_req_free(struct SingleRequest *req, struct Curl_easy *data);
+
+/**
+ * Reset the state of the request for new use, given the
+ * settings.
+ */
+void Curl_req_reset(struct SingleRequest *req, struct Curl_easy *data);
+
+
+#endif /* HEADER_CURL_REQUEST_H */
}
if(rtspreq == RTSPREQ_RECEIVE) {
- Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, -1);
+ Curl_xfer_setup(data, FIRSTSOCKET, -1, TRUE, -1);
return result;
}
return result;
}
- Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, putsize?FIRSTSOCKET:-1);
+ Curl_xfer_setup(data, FIRSTSOCKET, -1, TRUE, putsize?FIRSTSOCKET:-1);
/* Increment the CSeq on success */
data->state.rtsp_next_client_CSeq++;
static CURLcode do_init_stack(struct Curl_easy *data);
-/*
- * Curl_nwrite() is an internal write function that sends data to the
- * server. Works with a socket index for the connection.
- *
- * If the write would block (CURLE_AGAIN), it returns CURLE_OK and
- * (*nwritten == 0). Otherwise we return regular CURLcode value.
- */
-CURLcode Curl_nwrite(struct Curl_easy *data,
- int sockindex,
- const void *buf,
- size_t blen,
- ssize_t *pnwritten)
-{
- ssize_t nwritten;
- CURLcode result = CURLE_OK;
- struct connectdata *conn;
-
- DEBUGASSERT(sockindex >= 0 && sockindex < 2);
- DEBUGASSERT(pnwritten);
- DEBUGASSERT(data);
- DEBUGASSERT(data->conn);
- conn = data->conn;
-#ifdef CURLDEBUG
- {
- /* Allow debug builds to override this logic to force short sends
- */
- char *p = getenv("CURL_SMALLSENDS");
- if(p) {
- size_t altsize = (size_t)strtoul(p, NULL, 10);
- if(altsize)
- blen = CURLMIN(blen, altsize);
- }
- }
-#endif
- nwritten = conn->send[sockindex](data, sockindex, buf, blen, &result);
- if(result == CURLE_AGAIN) {
- nwritten = 0;
- result = CURLE_OK;
- }
- else if(result) {
- nwritten = -1; /* make sure */
- }
- else {
- DEBUGASSERT(nwritten >= 0);
- }
-
- *pnwritten = nwritten;
- return result;
-}
-
-/*
- * Curl_write() is an internal write function that sends data to the
- * server. Works with plain sockets, SCP, SSL or kerberos.
- *
- * If the write would block (CURLE_AGAIN), we return CURLE_OK and
- * (*written == 0). Otherwise we return regular CURLcode value.
- */
-CURLcode Curl_write(struct Curl_easy *data,
- curl_socket_t sockfd,
- const void *mem,
- size_t len,
- ssize_t *written)
-{
- struct connectdata *conn;
- int num;
-
- DEBUGASSERT(data);
- DEBUGASSERT(data->conn);
- conn = data->conn;
- num = (sockfd != CURL_SOCKET_BAD && sockfd == conn->sock[SECONDARYSOCKET]);
- return Curl_nwrite(data, num, mem, len, written);
-}
-
/* Curl_client_write() sends data to the write callback(s)
The bit pattern defines to what "streams" to write to. Body and/or header.
return Curl_cwriter_write(data, data->req.writer_stack, type, buf, blen);
}
-void Curl_client_cleanup(struct Curl_easy *data)
+void Curl_cw_reset(struct Curl_easy *data)
{
struct Curl_cwriter *writer = data->req.writer_stack;
}
}
-/*
- * Internal read-from-socket function. This is meant to deal with plain
- * sockets, SSL sockets and kerberos sockets.
- *
- * Returns a regular CURLcode value.
- */
-CURLcode Curl_read(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 = CURLE_RECV_ERROR;
- ssize_t nread = 0;
- size_t bytesfromsocket = 0;
- char *buffertofill = NULL;
- struct connectdata *conn = data->conn;
-
- /* Set 'num' to 0 or 1, depending on which socket that has been sent here.
- If it is the second socket, we set num to 1. Otherwise to 0. This lets
- us use the correct ssl handle. */
- int num = (sockfd == conn->sock[SECONDARYSOCKET]);
-
- *n = 0; /* reset amount to zero */
-
- bytesfromsocket = CURLMIN(sizerequested, (size_t)data->set.buffer_size);
- buffertofill = buf;
-
- nread = conn->recv[num](data, num, buffertofill, bytesfromsocket, &result);
- if(nread < 0)
- goto out;
-
- *n += nread;
- result = CURLE_OK;
-out:
- return result;
-}
/**
* Free all resources related to client writing.
*/
-void Curl_client_cleanup(struct Curl_easy *data);
+void Curl_cw_reset(struct Curl_easy *data);
/**
* Client Writers - a chain passing transfer BODY data to the client.
struct Curl_cwriter *writer);
-/* 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,
- ssize_t *n);
-
-/* internal write-function, does plain socket, SSL, SCP, SFTP and krb4 */
-CURLcode Curl_write(struct Curl_easy *data,
- curl_socket_t sockfd,
- const void *mem, size_t len,
- ssize_t *written);
-
-/* internal write-function, using sockindex for connection destination */
-CURLcode Curl_nwrite(struct Curl_easy *data,
- int sockindex,
- const void *buf,
- size_t blen,
- ssize_t *pnwritten);
-
#endif /* HEADER_CURL_SENDF_H */
static CURLcode smb_recv_message(struct Curl_easy *data, void **msg)
{
struct connectdata *conn = data->conn;
- curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
struct smb_conn *smbc = &conn->proto.smbc;
char *buf = smbc->recv_buf;
ssize_t bytes_read;
size_t len = MAX_MESSAGE_SIZE - smbc->got;
CURLcode result;
- result = Curl_read(data, sockfd, buf + smbc->got, len, &bytes_read);
+ result = Curl_xfer_recv(data, buf + smbc->got, len, &bytes_read);
if(result)
return result;
ssize_t bytes_written;
CURLcode result;
- result = Curl_nwrite(data, FIRSTSOCKET, data->state.ulbuf,
- len, &bytes_written);
+ result = Curl_xfer_send(data, data->state.ulbuf, len, &bytes_written);
if(result)
return result;
if(!smbc->send_size)
return CURLE_OK;
- result = Curl_nwrite(data, FIRSTSOCKET,
- data->state.ulbuf + smbc->sent,
- len, &bytes_written);
+ result = Curl_xfer_send(data, data->state.ulbuf + smbc->sent, len,
+ &bytes_written);
if(result)
return result;
Curl_pgrsSetUploadSize(data, data->state.infilesize);
/* SMTP upload */
- Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
+ Curl_xfer_setup(data, -1, -1, FALSE, FIRSTSOCKET);
/* End of DO phase */
smtp_state(data, SMTP_STOP);
struct connectdata *conn)
{
CURLcode result = CURLE_OK;
- curl_socket_t sock = conn->sock[FIRSTSOCKET];
int smtpcode;
struct smtp_conn *smtpc = &conn->proto.smtpc;
struct pingpong *pp = &smtpc->pp;
do {
/* Read the response from the server */
- result = Curl_pp_readresp(data, sock, pp, &smtpcode, &nread);
+ result = Curl_pp_readresp(data, FIRSTSOCKET, pp, &smtpcode, &nread);
if(result)
return result;
return CURLE_OUT_OF_MEMORY;
/* Send the end of block data */
- result = Curl_write(data, conn->writesockfd, eob, len, &bytes_written);
+ result = Curl_xfer_send(data, eob, len, &bytes_written);
if(result) {
free(eob);
return result;
if(smtp->transfer != PPTRANSFER_BODY)
/* no data to transfer */
- Curl_setup_transfer(data, -1, -1, FALSE, -1);
+ Curl_xfer_setup(data, -1, -1, FALSE, -1);
return CURLE_OK;
}
break;
default: /* write! */
bytes_written = 0;
- result = Curl_nwrite(data, FIRSTSOCKET, outbuf + total_written,
- outlen - total_written, &bytes_written);
+ result = Curl_xfer_send(data, outbuf + total_written,
+ outlen - total_written, &bytes_written);
total_written += bytes_written;
break;
}
}
if(events.lNetworkEvents & FD_READ) {
/* read data from network */
- result = Curl_read(data, sockfd, buffer, sizeof(buffer), &nread);
+ result = Curl_xfer_recv(data, buffer, sizeof(buffer), &nread);
/* read would've blocked. Loop again */
if(result == CURLE_AGAIN)
break;
default: /* read! */
if(pfd[0].revents & POLLIN) {
/* read data from network */
- result = Curl_read(data, sockfd, buffer, sizeof(buffer), &nread);
+ result = Curl_xfer_recv(data, buffer, sizeof(buffer), &nread);
/* read would've blocked. Loop again */
if(result == CURLE_AGAIN)
break;
}
#endif
/* mark this as "no further transfer wanted" */
- Curl_setup_transfer(data, -1, -1, FALSE, -1);
+ Curl_xfer_setup(data, -1, -1, FALSE, -1);
return result;
}
*done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE;
if(*done)
/* Tell curl we're done */
- Curl_setup_transfer(data, -1, -1, FALSE, -1);
+ Curl_xfer_setup(data, -1, -1, FALSE, -1);
}
else {
/* no timeouts to handle, check our socket */
*done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE;
if(*done)
/* Tell curl we're done */
- Curl_setup_transfer(data, -1, -1, FALSE, -1);
+ Curl_xfer_setup(data, -1, -1, FALSE, -1);
}
/* if rc == 0, then select() timed out */
}
return 0;
}
- *err = Curl_read(data, data->conn->sockfd, buf, blen, &nread);
+ *err = Curl_xfer_recv(data, buf, blen, &nread);
if(*err)
return -1;
DEBUGASSERT(nread >= 0);
that instead of reading more data */
}
+ if(!Curl_bufq_is_empty(&k->sendbuf)) {
+ DEBUGASSERT(0);
+ }
/* write to socket (send away data) */
- result = Curl_write(data,
- conn->writesockfd, /* socket to send to */
- k->upload_fromhere, /* buffer pointer */
- k->upload_present, /* buffer size */
- &bytes_written); /* actually sent */
+ result = Curl_xfer_send(data,
+ k->upload_fromhere, /* buffer pointer */
+ k->upload_present, /* buffer size */
+ &bytes_written); /* actually sent */
if(result)
return result;
}
/*
- * Curl_setup_transfer() is called to setup some basic properties for the
+ * Curl_xfer_setup() is called to setup some basic properties for the
* upcoming transfer.
*/
-void
-Curl_setup_transfer(
+void Curl_xfer_setup(
struct Curl_easy *data, /* transfer */
int sockindex, /* socket index to read from or -1 */
curl_off_t size, /* -1 if unknown at this point */
DEBUGASSERT(conn != NULL);
DEBUGASSERT((sockindex <= 1) && (sockindex >= -1));
+ DEBUGASSERT((writesockindex <= 1) && (writesockindex >= -1));
httpsending = ((conn->handler->protocol&PROTO_FAMILY_HTTP) &&
(http->sending == HTTPSEND_REQUEST));
(void)premature;
return Curl_cw_out_done(data);
}
+
+CURLcode Curl_xfer_send(struct Curl_easy *data,
+ const void *buf, size_t blen,
+ ssize_t *pnwritten)
+{
+ CURLcode result;
+ int sockindex;
+
+ if(!data || !data->conn)
+ return CURLE_FAILED_INIT;
+ /* FIXME: would like to enable this, but some protocols (MQTT) do not
+ * setup the transfer correctly, it seems
+ if(data->conn->writesockfd == CURL_SOCKET_BAD) {
+ failf(data, "transfer not setup for sending");
+ DEBUGASSERT(0);
+ return CURLE_SEND_ERROR;
+ } */
+ sockindex = ((data->conn->writesockfd != CURL_SOCKET_BAD) &&
+ (data->conn->writesockfd == data->conn->sock[SECONDARYSOCKET]));
+ result = Curl_conn_send(data, sockindex, buf, blen, pnwritten);
+ if(result == CURLE_AGAIN) {
+ result = CURLE_OK;
+ *pnwritten = 0;
+ }
+ return result;
+}
+
+CURLcode Curl_xfer_recv(struct Curl_easy *data,
+ char *buf, size_t blen,
+ ssize_t *pnrcvd)
+{
+ int sockindex;
+
+ if(!data || !data->conn)
+ return CURLE_FAILED_INIT;
+ /* FIXME: would like to enable this, but some protocols (MQTT) do not
+ * setup the transfer correctly, it seems
+ if(data->conn->sockfd == CURL_SOCKET_BAD) {
+ failf(data, "transfer not setup for receiving");
+ DEBUGASSERT(0);
+ return CURLE_RECV_ERROR;
+ } */
+ sockindex = ((data->conn->sockfd != CURL_SOCKET_BAD) &&
+ (data->conn->sockfd == data->conn->sock[SECONDARYSOCKET]));
+ if(data->set.buffer_size > 0 && (size_t)data->set.buffer_size < blen)
+ blen = (size_t)data->set.buffer_size;
+ return Curl_conn_recv(data, sockindex, buf, blen, pnrcvd);
+}
bool is_eos, bool *done);
/* This sets up a forthcoming transfer */
-void
-Curl_setup_transfer (struct Curl_easy *data,
+void Curl_xfer_setup(struct Curl_easy *data,
int sockindex, /* socket index to read from or -1 */
curl_off_t size, /* -1 if unknown at this point */
bool getheader, /* TRUE if header parsing is wanted */
*/
CURLcode Curl_xfer_write_done(struct Curl_easy *data, bool premature);
+/**
+ * Send data on the socket/connection filter designated
+ * for transfer's outgoing data.
+ * Will return CURLE_OK on blocking with (*pnwritten == 0).
+ */
+CURLcode Curl_xfer_send(struct Curl_easy *data,
+ const void *buf, size_t blen,
+ ssize_t *pnwritten);
+
+/**
+ * Receive data on the socket/connection filter designated
+ * for transfer's incoming data.
+ * Will return CURLE_AGAIN on blocking with (*pnrcvd == 0).
+ */
+CURLcode Curl_xfer_recv(struct Curl_easy *data,
+ char *buf, size_t blen,
+ ssize_t *pnrcvd);
+
#endif /* HEADER_CURL_TRANSFER_H */
free(data->state.range);
/* freed here just in case DONE wasn't called */
- Curl_free_request_state(data);
+ Curl_req_free(&data->req, data);
/* Close down all open SSL info and sessions */
Curl_ssl_close_all(data);
Curl_safefree(data->state.scratch);
Curl_ssl_free_certinfo(data);
- /* Cleanup possible redirect junk */
- free(data->req.newurl);
- data->req.newurl = NULL;
-
if(data->state.referer_alloc) {
Curl_safefree(data->state.referer);
data->state.referer_alloc = FALSE;
Curl_safefree(data->state.aptr.proxyuser);
Curl_safefree(data->state.aptr.proxypasswd);
-#ifndef CURL_DISABLE_DOH
- if(data->req.doh) {
- Curl_dyn_free(&data->req.doh->probe[0].serverdoh);
- Curl_dyn_free(&data->req.doh->probe[1].serverdoh);
- curl_slist_free_all(data->req.doh->headers);
- Curl_safefree(data->req.doh);
- }
-#endif
-
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_FORM_API)
Curl_mime_cleanpart(data->state.formp);
Curl_safefree(data->state.formp);
data->magic = CURLEASY_MAGIC_NUMBER;
+ result = Curl_req_init(&data->req);
+ if(result) {
+ DEBUGF(fprintf(stderr, "Error: request init failed\n"));
+ free(data);
+ return result;
+ }
+
result = Curl_resolver_init(data, &data->state.async.resolver);
if(result) {
DEBUGF(fprintf(stderr, "Error: resolver_init failed\n"));
+ Curl_req_free(&data->req, data);
free(data);
return result;
}
Curl_resolver_cleanup(data->state.async.resolver);
Curl_dyn_free(&data->state.headerb);
Curl_freeset(data);
+ Curl_req_free(&data->req, data);
free(data);
data = NULL;
}
return CURLE_OK;
}
-/*
- * Curl_free_request_state() should free temp data that was allocated in the
- * Curl_easy for this single request.
- */
-
-void Curl_free_request_state(struct Curl_easy *data)
-{
- Curl_safefree(data->req.p.http);
- Curl_safefree(data->req.newurl);
-#ifndef CURL_DISABLE_DOH
- if(data->req.doh) {
- Curl_close(&data->req.doh->probe[0].easy);
- Curl_close(&data->req.doh->probe[1].easy);
- }
-#endif
- Curl_client_cleanup(data);
-}
-
#ifndef CURL_DISABLE_PROXY
(void)conn->handler->done(data, result, FALSE);
goto out;
}
- Curl_setup_transfer(data, -1, -1, FALSE, -1);
+ Curl_xfer_setup(data, -1, -1, FALSE, -1);
}
/* since we skip do_init() */
#endif
/* Setup filter for network connections */
- conn->recv[FIRSTSOCKET] = Curl_conn_recv;
- conn->send[FIRSTSOCKET] = Curl_conn_send;
- conn->recv[SECONDARYSOCKET] = Curl_conn_recv;
- conn->send[SECONDARYSOCKET] = Curl_conn_send;
+ conn->recv[FIRSTSOCKET] = Curl_cf_recv;
+ conn->send[FIRSTSOCKET] = Curl_cf_send;
+ conn->recv[SECONDARYSOCKET] = Curl_cf_recv;
+ conn->send[SECONDARYSOCKET] = Curl_cf_send;
conn->bits.tcp_fastopen = data->set.tcp_fastopen;
/* Complete the easy's SSL configuration for connection cache matching */
*asyncp = FALSE; /* assume synchronous resolves by default */
/* init the single-transfer specific data */
- Curl_free_request_state(data);
+ Curl_req_reset(&data->req, data);
memset(&data->req, 0, sizeof(struct SingleRequest));
data->req.size = data->req.maxdownload = -1;
data->req.no_body = data->set.opt_no_body;
/* in HTTP lingo, no body means using the HEAD request... */
data->state.httpreq = HTTPREQ_HEAD;
- k->start = Curl_now(); /* start time */
+ result = Curl_req_start(&data->req, data);
+ if(result)
+ return result;
+
k->header = TRUE; /* assume header */
k->bytecount = 0;
k->ignorebody = FALSE;
- Curl_client_cleanup(data);
Curl_speedinit(data);
Curl_pgrsSetUploadCounter(data, 0);
Curl_pgrsSetDownloadCounter(data, 0);
struct connectdata *, bool dead_connection);
CURLcode Curl_setup_conn(struct Curl_easy *data,
bool *protocol_done);
-void Curl_free_request_state(struct Curl_easy *data);
CURLcode Curl_parse_login_details(const char *login, const size_t len,
char **userptr, char **passwdptr,
char **optionsptr);
#include "splay.h"
#include "dynbuf.h"
#include "dynhds.h"
+#include "request.h"
/* return the count of bytes sent, or -1 on error */
typedef ssize_t (Curl_send)(struct Curl_easy *data, /* transfer */
unsigned char actions[MAX_SOCKSPEREASYHANDLE];
};
-enum expect100 {
- EXP100_SEND_DATA, /* enough waiting, just send the body now */
- EXP100_AWAITING_CONTINUE, /* waiting for the 100 Continue header */
- EXP100_SENDING_REQUEST, /* still sending the request but will wait for
- the 100 header once done with the request */
- EXP100_FAILED /* used on 417 Expectation Failed */
-};
-
-enum upgrade101 {
- UPGR101_INIT, /* default state */
- UPGR101_WS, /* upgrade to WebSockets requested */
- UPGR101_H2, /* upgrade to HTTP/2 requested */
- UPGR101_RECEIVED, /* 101 response received */
- UPGR101_WORKING /* talking upgraded protocol */
-};
-
enum doh_slots {
/* Explicit values for first two symbols so as to match hard-coded
* constants in existing code
DOH_PROBE_SLOTS
};
-/*
- * Request specific data in the easy handle (Curl_easy). Previously,
- * these members were on the connectdata struct but since a conn struct may
- * now be shared between different Curl_easys, we store connection-specific
- * data here. This struct only keeps stuff that's interesting for *this*
- * request, as it will be cleared between multiple ones
- */
-struct SingleRequest {
- curl_off_t size; /* -1 if unknown at this point */
- curl_off_t maxdownload; /* in bytes, the maximum amount of data to fetch,
- -1 means unlimited */
- curl_off_t bytecount; /* total number of bytes read */
- curl_off_t writebytecount; /* number of bytes written */
-
- curl_off_t pendingheader; /* this many bytes left to send is actually
- header and not body */
- struct curltime start; /* transfer started at this time */
- unsigned int headerbytecount; /* received server headers (not CONNECT
- headers) */
- unsigned int allheadercount; /* all received headers (server + CONNECT) */
- unsigned int deductheadercount; /* this amount of bytes doesn't count when
- we check if anything has been transferred
- at the end of a connection. We use this
- counter to make only a 100 reply (without
- a following second response code) result
- in a CURLE_GOT_NOTHING error code */
- int headerline; /* counts header lines to better track the
- first one */
- curl_off_t offset; /* possible resume offset read from the
- Content-Range: header */
- int httpcode; /* error code from the 'HTTP/1.? XXX' or
- 'RTSP/1.? XXX' line */
- int keepon;
- struct curltime start100; /* time stamp to wait for the 100 code from */
- enum expect100 exp100; /* expect 100 continue state */
- enum upgrade101 upgr101; /* 101 upgrade state */
-
- /* Client Writer stack, handles trasnfer- and content-encodings, protocol
- * checks, pausing by client callbacks. */
- struct Curl_cwriter *writer_stack;
- time_t timeofdoc;
- long bodywrites;
- char *location; /* This points to an allocated version of the Location:
- header data */
- char *newurl; /* Set to the new URL to use when a redirect or a retry is
- wanted */
-
- /* 'upload_present' is used to keep a byte counter of how much data there is
- still left in the buffer, aimed for upload. */
- ssize_t upload_present;
-
- /* 'upload_fromhere' is used as a read-pointer when we uploaded parts of a
- buffer, so the next read should read from where this pointer points to,
- and the 'upload_present' contains the number of bytes available at this
- position */
- char *upload_fromhere;
-
- /* Allocated protocol-specific data. Each protocol handler makes sure this
- points to data it needs. */
- union {
- struct FILEPROTO *file;
- struct FTP *ftp;
- struct HTTP *http;
- struct IMAP *imap;
- struct ldapreqinfo *ldap;
- struct MQTT *mqtt;
- struct POP3 *pop3;
- struct RTSP *rtsp;
- struct smb_request *smb;
- struct SMTP *smtp;
- struct SSHPROTO *ssh;
- struct TELNET *telnet;
- } p;
-#ifndef CURL_DISABLE_DOH
- struct dohdata *doh; /* DoH specific data for this request */
-#endif
- char fread_eof[2]; /* the body read callback (index 0) returned EOF or
- the trailer read callback (index 1) returned EOF */
-#ifndef CURL_DISABLE_COOKIES
- unsigned char setcookies;
-#endif
- BIT(header); /* incoming data has HTTP header */
- BIT(content_range); /* set TRUE if Content-Range: was found */
- BIT(download_done); /* set to TRUE when download is complete */
- BIT(eos_written); /* iff EOS has been written to client */
- BIT(upload_done); /* set to TRUE when doing chunked transfer-encoding
- upload and we're uploading the last chunk */
- BIT(ignorebody); /* we read a response-body but we ignore it! */
- BIT(http_bodyless); /* HTTP response status code is between 100 and 199,
- 204 or 304 */
- BIT(chunk); /* if set, this is a chunked transfer-encoding */
- BIT(ignore_cl); /* ignore content-length */
- BIT(upload_chunky); /* set TRUE if we are doing chunked transfer-encoding
- on upload */
- BIT(getheader); /* TRUE if header parsing is wanted */
- BIT(forbidchunk); /* used only to explicitly forbid chunk-upload for
- specific upload buffers. See readmoredata() in http.c
- for details. */
- BIT(no_body); /* the response has no body */
- BIT(authneg); /* TRUE when the auth phase has started, which means
- that we are creating a request with an auth header,
- but it is not the final request in the auth
- negotiation. */
-};
-
/*
* Specific protocol handler.
*/
Curl_pgrsSetUploadSize(data, data->state.infilesize);
}
/* upload data */
- Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
+ Curl_xfer_setup(data, -1, -1, FALSE, FIRSTSOCKET);
- /* not set by Curl_setup_transfer to preserve keepon bits */
+ /* not set by Curl_xfer_setup to preserve keepon bits */
conn->sockfd = conn->writesockfd;
/* store this original bitmask setup to use later on if we can't
sshc->sftp_dir = NULL;
/* no data to transfer */
- Curl_setup_transfer(data, -1, -1, FALSE, -1);
+ Curl_xfer_setup(data, -1, -1, FALSE, -1);
state(data, SSH_STOP);
break;
/* Setup the actual download */
if(data->req.size == 0) {
/* no data to transfer */
- Curl_setup_transfer(data, -1, -1, FALSE, -1);
+ Curl_xfer_setup(data, -1, -1, FALSE, -1);
infof(data, "File already completely downloaded");
state(data, SSH_STOP);
break;
}
- Curl_setup_transfer(data, FIRSTSOCKET, data->req.size, FALSE, -1);
+ Curl_xfer_setup(data, FIRSTSOCKET, data->req.size, FALSE, -1);
- /* not set by Curl_setup_transfer to preserve keepon bits */
+ /* not set by Curl_xfer_setup to preserve keepon bits */
conn->writesockfd = conn->sockfd;
/* we want to use the _receiving_ function even when the socket turns
}
/* upload data */
- Curl_setup_transfer(data, -1, data->req.size, FALSE, FIRSTSOCKET);
+ Curl_xfer_setup(data, -1, data->req.size, FALSE, FIRSTSOCKET);
- /* not set by Curl_setup_transfer to preserve keepon bits */
+ /* not set by Curl_xfer_setup to preserve keepon bits */
conn->sockfd = conn->writesockfd;
/* store this original bitmask setup to use later on if we can't
/* download data */
bytecount = ssh_scp_request_get_size(sshc->scp_session);
data->req.maxdownload = (curl_off_t) bytecount;
- Curl_setup_transfer(data, FIRSTSOCKET, bytecount, FALSE, -1);
+ Curl_xfer_setup(data, FIRSTSOCKET, bytecount, FALSE, -1);
- /* not set by Curl_setup_transfer to preserve keepon bits */
+ /* not set by Curl_xfer_setup to preserve keepon bits */
conn->writesockfd = conn->sockfd;
/* we want to use the _receiving_ function even when the socket turns
Curl_pgrsSetUploadSize(data, data->state.infilesize);
}
/* upload data */
- Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
+ Curl_xfer_setup(data, -1, -1, FALSE, FIRSTSOCKET);
- /* not set by Curl_setup_transfer to preserve keepon bits */
+ /* not set by Curl_xfer_setup to preserve keepon bits */
conn->sockfd = conn->writesockfd;
if(result) {
Curl_safefree(sshp->readdir_longentry);
/* no data to transfer */
- Curl_setup_transfer(data, -1, -1, FALSE, -1);
+ Curl_xfer_setup(data, -1, -1, FALSE, -1);
state(data, SSH_STOP);
break;
/* Setup the actual download */
if(data->req.size == 0) {
/* no data to transfer */
- Curl_setup_transfer(data, -1, -1, FALSE, -1);
+ Curl_xfer_setup(data, -1, -1, FALSE, -1);
infof(data, "File already completely downloaded");
state(data, SSH_STOP);
break;
}
- Curl_setup_transfer(data, FIRSTSOCKET, data->req.size, FALSE, -1);
+ Curl_xfer_setup(data, FIRSTSOCKET, data->req.size, FALSE, -1);
- /* not set by Curl_setup_transfer to preserve keepon bits */
+ /* not set by Curl_xfer_setup to preserve keepon bits */
conn->writesockfd = conn->sockfd;
/* we want to use the _receiving_ function even when the socket turns
/* upload data */
data->req.size = data->state.infilesize;
Curl_pgrsSetUploadSize(data, data->state.infilesize);
- Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
+ Curl_xfer_setup(data, -1, -1, FALSE, FIRSTSOCKET);
- /* not set by Curl_setup_transfer to preserve keepon bits */
+ /* not set by Curl_xfer_setup to preserve keepon bits */
conn->sockfd = conn->writesockfd;
if(result) {
/* download data */
bytecount = (curl_off_t)sb.st_size;
data->req.maxdownload = (curl_off_t)sb.st_size;
- Curl_setup_transfer(data, FIRSTSOCKET, bytecount, FALSE, -1);
+ Curl_xfer_setup(data, FIRSTSOCKET, bytecount, FALSE, -1);
- /* not set by Curl_setup_transfer to preserve keepon bits */
+ /* not set by Curl_xfer_setup to preserve keepon bits */
conn->writesockfd = conn->sockfd;
/* we want to use the _receiving_ function even when the socket turns
struct connectdata *conn = data->conn;
Curl_recv *backup = conn->recv[0];
struct ssh_conn *ssh = &conn->proto.sshc;
+ int socknum = Curl_conn_sockindex(data, sock);
(void)flags;
/* swap in the TLS reader function for this call only, and then swap back
the SSH one again */
conn->recv[0] = ssh->tls_recv;
- result = Curl_read(data, sock, buffer, length, &nread);
+ result = Curl_conn_recv(data, socknum, buffer, length, &nread);
conn->recv[0] = backup;
if(result == CURLE_AGAIN)
return -EAGAIN; /* magic return code for libssh2 */
struct connectdata *conn = data->conn;
Curl_send *backup = conn->send[0];
struct ssh_conn *ssh = &conn->proto.sshc;
+ int socknum = Curl_conn_sockindex(data, sock);
(void)flags;
/* swap in the TLS writer function for this call only, and then swap back
the SSH one again */
conn->send[0] = ssh->tls_send;
- result = Curl_write(data, sock, buffer, length, &nwrite);
+ result = Curl_conn_send(data, socknum, buffer, length, &nwrite);
conn->send[0] = backup;
if(result == CURLE_AGAIN)
return -EAGAIN; /* magic return code for libssh2 */
Curl_pgrsSetUploadSize(data, data->state.infilesize);
}
/* upload data */
- Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
+ Curl_xfer_setup(data, -1, -1, FALSE, FIRSTSOCKET);
- /* not set by Curl_setup_transfer to preserve keepon bits */
+ /* not set by Curl_xfer_setup to preserve keepon bits */
conn->sockfd = conn->writesockfd;
if(result) {
/* Setup the actual download */
if(data->req.size == 0) {
/* no data to transfer */
- Curl_setup_transfer(data, -1, -1, FALSE, -1);
+ Curl_xfer_setup(data, -1, -1, FALSE, -1);
infof(data, "File already completely downloaded");
state(data, SSH_STOP);
break;
}
- Curl_setup_transfer(data, FIRSTSOCKET, data->req.size, FALSE, -1);
+ Curl_xfer_setup(data, FIRSTSOCKET, data->req.size, FALSE, -1);
- /* not set by Curl_setup_transfer to preserve keepon bits */
+ /* not set by Curl_xfer_setup to preserve keepon bits */
conn->writesockfd = conn->sockfd;
/* we want to use the _receiving_ function even when the socket turns
while(Curl_bufq_peek(&ws->sendbuf, &out, &outlen)) {
if(data->set.connect_only)
result = Curl_senddata(data, out, outlen, &n);
- else
- result = Curl_write(data, data->conn->writesockfd, out, outlen, &n);
+ else {
+ result = Curl_xfer_send(data, out, outlen, &n);
+ if(!result && !n && outlen)
+ result = CURLE_AGAIN;
+ }
+
if(result) {
if(result == CURLE_AGAIN) {
if(!complete) {
/* raw mode sends exactly what was requested, and this is from within
the write callback */
if(Curl_is_in_callback(data)) {
- result = Curl_write(data, data->conn->writesockfd, buffer, buflen,
- &nwritten);
+ result = Curl_xfer_send(data, buffer, buflen, &nwritten);
}
else
result = Curl_senddata(data, buffer, buflen, &nwritten);
return result;
/* TODO: the current design does not allow partial writes, afaict.
- * It is not clear who the application is supposed to react. */
+ * It is not clear how the application is supposed to react. */
space = Curl_bufq_space(&ws->sendbuf);
DEBUGF(infof(data, "curl_ws_send(len=%zu), sendbuf len=%zu space %zu",
buflen, Curl_bufq_len(&ws->sendbuf), space));
"Curl_free() did not set to NULL");
}
- Curl_free_request_state(empty);
-
rc = Curl_close(&empty);
fail_unless(rc == CURLE_OK, "Curl_close() failed");