diff options
Diffstat (limited to 'lib')
38 files changed, 447 insertions, 490 deletions
diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c index 375f1a6eb..815d7ab57 100644 --- a/lib/asyn-ares.c +++ b/lib/asyn-ares.c @@ -237,26 +237,6 @@ CURLcode Curl_async_get_impl(struct Curl_easy *data, void **impl) return result; } -static void async_ares_cleanup(struct Curl_easy *data); - -void Curl_async_ares_shutdown(struct Curl_easy *data) -{ - struct async_ares_ctx *ares = &data->state.async.ares; - if(ares->channel) - ares_cancel(ares->channel); - async_ares_cleanup(data); -} - -void Curl_async_ares_destroy(struct Curl_easy *data) -{ - struct async_ares_ctx *ares = &data->state.async.ares; - Curl_async_ares_shutdown(data); - if(ares->channel) { - ares_destroy(ares->channel); - ares->channel = NULL; - } -} - /* * async_ares_cleanup() cleans up async resolver data. */ @@ -272,6 +252,26 @@ static void async_ares_cleanup(struct Curl_easy *data) #endif } +void Curl_async_ares_shutdown(struct Curl_easy *data) +{ + /* c-ares has a method to "cancel" operations on a channel, but + * as reported in #18216, this does not totally reset the channel + * and ares may get stuck. + * We need to destroy the channel and on demand create a new + * one to avoid that. */ + Curl_async_ares_destroy(data); +} + +void Curl_async_ares_destroy(struct Curl_easy *data) +{ + struct async_ares_ctx *ares = &data->state.async.ares; + if(ares->channel) { + ares_destroy(ares->channel); + ares->channel = NULL; + } + async_ares_cleanup(data); +} + /* * Curl_async_pollset() is called when someone from the outside world * (using curl_multi_fdset()) wants to get our fd_set setup. diff --git a/lib/asyn-thrdd.c b/lib/asyn-thrdd.c index 6a56f92c4..82ce2b046 100644 --- a/lib/asyn-thrdd.c +++ b/lib/asyn-thrdd.c @@ -368,6 +368,14 @@ static CURLcode async_rr_start(struct Curl_easy *data) thrdd->rr.channel = NULL; return CURLE_FAILED_INIT; } +#ifdef CURLDEBUG + if(getenv("CURL_DNS_SERVER")) { + const char *servers = getenv("CURL_DNS_SERVER"); + status = ares_set_servers_ports_csv(thrdd->rr.channel, servers); + if(status) + return CURLE_FAILED_INIT; + } +#endif memset(&thrdd->rr.hinfo, 0, sizeof(thrdd->rr.hinfo)); thrdd->rr.hinfo.port = -1; @@ -375,6 +383,7 @@ static CURLcode async_rr_start(struct Curl_easy *data) data->conn->host.name, ARES_CLASS_IN, ARES_REC_TYPE_HTTPS, async_thrdd_rr_done, data, NULL); + CURL_TRC_DNS(data, "Issued HTTPS-RR request for %s", data->conn->host.name); return CURLE_OK; } #endif diff --git a/lib/cf-socket.c b/lib/cf-socket.c index 7f3f8e60f..426caf82d 100644 --- a/lib/cf-socket.c +++ b/lib/cf-socket.c @@ -109,7 +109,7 @@ static void set_ipv6_v6only(curl_socket_t sockfd, int on) static void tcpnodelay(struct Curl_easy *data, curl_socket_t sockfd) { -#ifdef TCP_NODELAY +#if defined(TCP_NODELAY) && defined(CURL_TCP_NODELAY_SUPPORTED) curl_socklen_t onoff = (curl_socklen_t) 1; int level = IPPROTO_TCP; char buffer[STRERROR_LEN]; diff --git a/lib/cfilters.c b/lib/cfilters.c index e4b630bc8..efd2ac6f6 100644 --- a/lib/cfilters.c +++ b/lib/cfilters.c @@ -177,6 +177,10 @@ CURLcode Curl_conn_shutdown(struct Curl_easy *data, int sockindex, bool *done) struct curltime now; DEBUGASSERT(data->conn); + + if(!CONN_SOCK_IDX_VALID(sockindex)) + return CURLE_BAD_FUNCTION_ARGUMENT; + /* Get the first connected filter that is not shut down already. */ cf = data->conn->cfilter[sockindex]; while(cf && (!cf->connected || cf->shutdown)) @@ -477,6 +481,8 @@ CURLcode Curl_conn_connect(struct Curl_easy *data, DEBUGASSERT(data); DEBUGASSERT(data->conn); + if(!CONN_SOCK_IDX_VALID(sockindex)) + return CURLE_BAD_FUNCTION_ARGUMENT; cf = data->conn->cfilter[sockindex]; if(!cf) { @@ -568,6 +574,8 @@ out: bool Curl_conn_is_setup(struct connectdata *conn, int sockindex) { + if(!CONN_SOCK_IDX_VALID(sockindex)) + return FALSE; return (conn->cfilter[sockindex] != NULL); } @@ -575,6 +583,8 @@ bool Curl_conn_is_connected(struct connectdata *conn, int sockindex) { struct Curl_cfilter *cf; + if(!CONN_SOCK_IDX_VALID(sockindex)) + return FALSE; cf = conn->cfilter[sockindex]; return cf && cf->connected; } @@ -583,6 +593,8 @@ bool Curl_conn_is_ip_connected(struct Curl_easy *data, int sockindex) { struct Curl_cfilter *cf; + if(!CONN_SOCK_IDX_VALID(sockindex)) + return FALSE; cf = data->conn->cfilter[sockindex]; while(cf) { if(cf->connected) @@ -607,6 +619,8 @@ static bool cf_is_ssl(struct Curl_cfilter *cf) bool Curl_conn_is_ssl(struct connectdata *conn, int sockindex) { + if(!CONN_SOCK_IDX_VALID(sockindex)) + return FALSE; return conn ? cf_is_ssl(conn->cfilter[sockindex]) : FALSE; } @@ -614,6 +628,8 @@ bool Curl_conn_get_ssl_info(struct Curl_easy *data, struct connectdata *conn, int sockindex, struct curl_tlssessioninfo *info) { + if(!CONN_SOCK_IDX_VALID(sockindex)) + return FALSE; if(Curl_conn_is_ssl(conn, sockindex)) { struct Curl_cfilter *cf = conn->cfilter[sockindex]; CURLcode result = cf ? cf->cft->query(cf, data, CF_QUERY_SSL_INFO, @@ -627,13 +643,20 @@ CURLcode Curl_conn_get_ip_info(struct Curl_easy *data, struct connectdata *conn, int sockindex, bool *is_ipv6, struct ip_quadruple *ipquad) { - struct Curl_cfilter *cf = conn ? conn->cfilter[sockindex] : NULL; + struct Curl_cfilter *cf; + if(!CONN_SOCK_IDX_VALID(sockindex)) + return CURLE_BAD_FUNCTION_ARGUMENT; + cf = conn ? conn->cfilter[sockindex] : NULL; return Curl_conn_cf_get_ip_info(cf, data, is_ipv6, ipquad); } bool Curl_conn_is_multiplex(struct connectdata *conn, int sockindex) { - struct Curl_cfilter *cf = conn ? conn->cfilter[sockindex] : NULL; + struct Curl_cfilter *cf; + + if(!CONN_SOCK_IDX_VALID(sockindex)) + return FALSE; + cf = conn ? conn->cfilter[sockindex] : NULL; for(; cf; cf = cf->next) { if(cf->cft->flags & CF_TYPE_MULTIPLEX) @@ -689,6 +712,8 @@ bool Curl_conn_data_pending(struct Curl_easy *data, int sockindex) (void)data; DEBUGASSERT(data); DEBUGASSERT(data->conn); + if(!CONN_SOCK_IDX_VALID(sockindex)) + return FALSE; cf = data->conn->cfilter[sockindex]; while(cf && !cf->connected) { @@ -712,6 +737,8 @@ bool Curl_conn_cf_needs_flush(struct Curl_cfilter *cf, bool Curl_conn_needs_flush(struct Curl_easy *data, int sockindex) { + if(!CONN_SOCK_IDX_VALID(sockindex)) + return FALSE; return Curl_conn_cf_needs_flush(data->conn->cfilter[sockindex], data); } @@ -774,8 +801,14 @@ void Curl_conn_get_current_host(struct Curl_easy *data, int sockindex, { struct Curl_cfilter *cf, *cf_proxy = NULL; - DEBUGASSERT(data->conn); - cf = data->conn->cfilter[sockindex]; + if(!data->conn) { + DEBUGASSERT(0); + *phost = ""; + *pport = -1; + return; + } + + cf = CONN_SOCK_IDX_VALID(sockindex) ? data->conn->cfilter[sockindex] : NULL; /* Find the "lowest" tunneling proxy filter that has not connected yet. */ while(cf && !cf->connected) { if((cf->cft->flags & (CF_TYPE_IP_CONNECT|CF_TYPE_PROXY)) == @@ -877,29 +910,33 @@ CURLcode Curl_conn_cf_get_ip_info(struct Curl_cfilter *cf, return result; } -curl_socket_t Curl_conn_get_socket(struct Curl_easy *data, int sockindex) +curl_socket_t Curl_conn_get_first_socket(struct Curl_easy *data) { struct Curl_cfilter *cf; - cf = data->conn ? data->conn->cfilter[sockindex] : NULL; + if(!data->conn) + return CURL_SOCKET_BAD; + + cf = data->conn->cfilter[FIRSTSOCKET]; /* if the top filter has not connected, ask it (and its sub-filters) - * for the socket. Otherwise conn->sock[sockindex] should have it. - */ + * for the socket. Otherwise conn->sock[sockindex] should have it. */ if(cf && !cf->connected) return Curl_conn_cf_get_socket(cf, data); - return data->conn ? data->conn->sock[sockindex] : CURL_SOCKET_BAD; + return data->conn->sock[FIRSTSOCKET]; } const struct Curl_sockaddr_ex * Curl_conn_get_remote_addr(struct Curl_easy *data, int sockindex) { - struct Curl_cfilter *cf = data->conn ? data->conn->cfilter[sockindex] : NULL; + struct Curl_cfilter *cf = + (data->conn && CONN_SOCK_IDX_VALID(sockindex)) ? + data->conn->cfilter[sockindex] : NULL; return cf ? cf_get_remote_addr(cf, data) : NULL; } void Curl_conn_forget_socket(struct Curl_easy *data, int sockindex) { - if(data->conn) { + if(data->conn && CONN_SOCK_IDX_VALID(sockindex)) { struct Curl_cfilter *cf = data->conn->cfilter[sockindex]; if(cf) (void)Curl_conn_cf_cntrl(cf, data, TRUE, @@ -941,6 +978,8 @@ CURLcode Curl_conn_ev_data_idle(struct Curl_easy *data) CURLcode Curl_conn_flush(struct Curl_easy *data, int sockindex) { + if(!CONN_SOCK_IDX_VALID(sockindex)) + return CURLE_BAD_FUNCTION_ARGUMENT; return Curl_conn_cf_cntrl(data->conn->cfilter[sockindex], data, FALSE, CF_CTRL_FLUSH, 0, NULL); } @@ -1010,7 +1049,11 @@ CURLcode Curl_conn_keep_alive(struct Curl_easy *data, struct connectdata *conn, int sockindex) { - struct Curl_cfilter *cf = conn->cfilter[sockindex]; + struct Curl_cfilter *cf; + + if(!CONN_SOCK_IDX_VALID(sockindex)) + return CURLE_BAD_FUNCTION_ARGUMENT; + cf = conn->cfilter[sockindex]; return cf ? cf->cft->keep_alive(cf, data) : CURLE_OK; } @@ -1018,10 +1061,14 @@ size_t Curl_conn_get_max_concurrent(struct Curl_easy *data, struct connectdata *conn, int sockindex) { + struct Curl_cfilter *cf; CURLcode result; int n = -1; - struct Curl_cfilter *cf = conn->cfilter[sockindex]; + if(!CONN_SOCK_IDX_VALID(sockindex)) + return 0; + + cf = conn->cfilter[sockindex]; result = cf ? cf->cft->query(cf, data, CF_QUERY_MAX_CONCURRENT, &n, NULL) : CURLE_UNKNOWN_OPTION; /* If no filter answered the query, the default is a non-multiplexed @@ -1034,10 +1081,14 @@ int Curl_conn_get_stream_error(struct Curl_easy *data, struct connectdata *conn, int sockindex) { + struct Curl_cfilter *cf; CURLcode result; int n = 0; - struct Curl_cfilter *cf = conn->cfilter[sockindex]; + if(!CONN_SOCK_IDX_VALID(sockindex)) + return 0; + + cf = conn->cfilter[sockindex]; result = cf ? cf->cft->query(cf, data, CF_QUERY_STREAM_ERROR, &n, NULL) : CURLE_UNKNOWN_OPTION; return (result || n < 0) ? 0 : n; @@ -1056,6 +1107,8 @@ CURLcode Curl_conn_recv(struct Curl_easy *data, int sockindex, { DEBUGASSERT(data); DEBUGASSERT(data->conn); + if(!CONN_SOCK_IDX_VALID(sockindex)) + return CURLE_BAD_FUNCTION_ARGUMENT; if(data && data->conn && data->conn->recv[sockindex]) return data->conn->recv[sockindex](data, sockindex, buf, blen, pnread); *pnread = 0; @@ -1070,7 +1123,9 @@ CURLcode Curl_conn_send(struct Curl_easy *data, int sockindex, DEBUGASSERT(data); DEBUGASSERT(data->conn); - DEBUGASSERT(sockindex >= 0 && sockindex < 2); + DEBUGASSERT(CONN_SOCK_IDX_VALID(sockindex)); + if(!CONN_SOCK_IDX_VALID(sockindex)) + return CURLE_BAD_FUNCTION_ARGUMENT; #ifdef DEBUGBUILD if(write_len) { /* Allow debug builds to override this logic to force short sends diff --git a/lib/cfilters.h b/lib/cfilters.h index 458ce5893..815b72a6e 100644 --- a/lib/cfilters.h +++ b/lib/cfilters.h @@ -460,10 +460,11 @@ bool Curl_conn_needs_flush(struct Curl_easy *data, int sockindex); CURLcode Curl_conn_flush(struct Curl_easy *data, int sockindex); /** - * Return the socket used on data's connection for the index. + * Return the socket used on data's connection for FIRSTSOCKET, + * querying filters if the whole chain has not connected yet. * Returns CURL_SOCKET_BAD if not available. */ -curl_socket_t Curl_conn_get_socket(struct Curl_easy *data, int sockindex); +curl_socket_t Curl_conn_get_first_socket(struct Curl_easy *data); /* Return a pointer to the connected socket address or NULL. */ const struct Curl_sockaddr_ex * diff --git a/lib/curl_rtmp.c b/lib/curl_rtmp.c index 584c8a9df..b178dff84 100644 --- a/lib/curl_rtmp.c +++ b/lib/curl_rtmp.c @@ -296,10 +296,10 @@ static CURLcode rtmp_do(struct Curl_easy *data, bool *done) if(data->state.upload) { Curl_pgrsSetUploadSize(data, data->state.infilesize); - Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE); + Curl_xfer_setup_send(data, FIRSTSOCKET); } else - Curl_xfer_setup1(data, CURL_XFER_RECV, -1, FALSE); + Curl_xfer_setup_recv(data, FIRSTSOCKET, -1); *done = TRUE; return CURLE_OK; } diff --git a/lib/curl_setup.h b/lib/curl_setup.h index 9b663fcb7..0a6591db8 100644 --- a/lib/curl_setup.h +++ b/lib/curl_setup.h @@ -1125,6 +1125,11 @@ int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf, #define USE_HTTP3 #endif +/* WebAssembly builds have TCP_NODELAY, but runtime support is missing. */ +#ifndef __EMSCRIPTEN__ +#define CURL_TCP_NODELAY_SUPPORTED +#endif + /* Certain Windows implementations are not aligned with what curl expects, so always use the local one on this platform. E.g. the mingw-w64 implementation can return wrong results for non-ASCII inputs. */ diff --git a/lib/curlx/dynbuf.c b/lib/curlx/dynbuf.c index cd4f4635a..447203e42 100644 --- a/lib/curlx/dynbuf.c +++ b/lib/curlx/dynbuf.c @@ -231,6 +231,7 @@ CURLcode curlx_dyn_addf(struct dynbuf *s, const char *fmt, ...) DEBUGASSERT(s); DEBUGASSERT(s->init == DYNINIT); DEBUGASSERT(!s->leng || s->bufr); + DEBUGASSERT(strcmp(fmt, "%s")); /* use curlx_dyn_add instead */ va_start(ap, fmt); result = curlx_dyn_vaddf(s, fmt, ap); va_end(ap); diff --git a/lib/dict.c b/lib/dict.c index 30e13b454..819584f28 100644 --- a/lib/dict.c +++ b/lib/dict.c @@ -242,7 +242,7 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done) failf(data, "Failed sending DICT request"); goto error; } - Curl_xfer_setup1(data, CURL_XFER_RECV, -1, FALSE); /* no upload */ + Curl_xfer_setup_recv(data, FIRSTSOCKET, -1); } else if(curl_strnequal(path, DICT_DEFINE, sizeof(DICT_DEFINE)-1) || curl_strnequal(path, DICT_DEFINE2, sizeof(DICT_DEFINE2)-1) || @@ -283,7 +283,7 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done) failf(data, "Failed sending DICT request"); goto error; } - Curl_xfer_setup1(data, CURL_XFER_RECV, -1, FALSE); + Curl_xfer_setup_recv(data, FIRSTSOCKET, -1); } else { @@ -305,7 +305,7 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done) goto error; } - Curl_xfer_setup1(data, CURL_XFER_RECV, -1, FALSE); + Curl_xfer_setup_recv(data, FIRSTSOCKET, -1); } } @@ -546,12 +546,13 @@ static CURLcode ftp_initiate_transfer(struct Curl_easy *data, /* FTP upload, shutdown DATA, ignore shutdown errors, as we rely * on the server response on the CONTROL connection. */ - Curl_xfer_setup2(data, CURL_XFER_SEND, -1, TRUE, TRUE); + Curl_xfer_setup_send(data, SECONDARYSOCKET); + Curl_xfer_set_shutdown(data, TRUE, TRUE); } else { /* FTP download, shutdown, do not ignore errors */ - Curl_xfer_setup2(data, CURL_XFER_RECV, - ftpc->retr_size_saved, TRUE, FALSE); + Curl_xfer_setup_recv(data, SECONDARYSOCKET, ftpc->retr_size_saved); + Curl_xfer_set_shutdown(data, TRUE, FALSE); } ftpc->pp.pending_resp = TRUE; /* expect server response */ diff --git a/lib/gopher.c b/lib/gopher.c index 82e02ed17..93db85e9d 100644 --- a/lib/gopher.c +++ b/lib/gopher.c @@ -240,7 +240,7 @@ static CURLcode gopher_do(struct Curl_easy *data, bool *done) if(result) return result; - Curl_xfer_setup1(data, CURL_XFER_RECV, -1, FALSE); + Curl_xfer_setup_recv(data, FIRSTSOCKET, -1); return CURLE_OK; } #endif /* CURL_DISABLE_GOPHER */ diff --git a/lib/hostip.c b/lib/hostip.c index 06fa3bc47..6ad961ff8 100644 --- a/lib/hostip.c +++ b/lib/hostip.c @@ -202,6 +202,8 @@ dnscache_entry_is_stale(void *datap, void *hc) if(dns->timestamp.tv_sec || dns->timestamp.tv_usec) { /* get age in milliseconds */ timediff_t age = curlx_timediff(prune->now, dns->timestamp); + if(!dns->addr) + age *= 2; /* negative entries age twice as fast */ if(age >= prune->max_age_ms) return TRUE; if(age > prune->oldest_ms) @@ -215,7 +217,7 @@ dnscache_entry_is_stale(void *datap, void *hc) * Returns the 'age' of the oldest still kept entry - in milliseconds. */ static timediff_t -dnscache_prune(struct Curl_hash *hostcache, int cache_timeout_ms, +dnscache_prune(struct Curl_hash *hostcache, timediff_t cache_timeout_ms, struct curltime now) { struct dnscache_prune_data user; @@ -263,7 +265,7 @@ void Curl_dnscache_prune(struct Curl_easy *data) struct Curl_dnscache *dnscache = dnscache_get(data); struct curltime now; /* the timeout may be set -1 (forever) */ - int timeout_ms = data->set.dns_cache_timeout_ms; + timediff_t timeout_ms = data->set.dns_cache_timeout_ms; if(!dnscache || (timeout_ms == -1)) /* NULL hostcache means we cannot do it */ @@ -798,6 +800,28 @@ static bool can_resolve_ip_version(struct Curl_easy *data, int ip_version) return TRUE; } +static CURLcode store_negative_resolve(struct Curl_easy *data, + const char *host, + int port) +{ + struct Curl_dnscache *dnscache = dnscache_get(data); + struct Curl_dns_entry *dns; + DEBUGASSERT(dnscache); + if(!dnscache) + return CURLE_FAILED_INIT; + + /* put this new host in the cache */ + dns = dnscache_add_addr(data, dnscache, NULL, host, 0, port, FALSE); + if(dns) { + /* release the returned reference; the cache itself will keep the + * entry alive: */ + dns->refcount--; + infof(data, "Store negative name resolve for %s:%d", host, port); + return CURLE_OK; + } + return CURLE_OUT_OF_MEMORY; +} + /* * Curl_resolv() is the main name resolve function within libcurl. It resolves * a name and returns a pointer to the entry in the 'entry' argument (if one @@ -917,6 +941,11 @@ out: * or `respwait` is set for an async operation. * Everything else is a failure to resolve. */ if(dns) { + if(!dns->addr) { + infof(data, "Negative DNS entry"); + dns->refcount--; + return CURLE_COULDNT_RESOLVE_HOST; + } *entry = dns; return CURLE_OK; } @@ -942,6 +971,7 @@ error: Curl_resolv_unlink(data, &dns); *entry = NULL; Curl_async_shutdown(data); + store_negative_resolve(data, hostname, port); return CURLE_COULDNT_RESOLVE_HOST; } @@ -1523,6 +1553,9 @@ CURLcode Curl_resolv_check(struct Curl_easy *data, result = Curl_async_is_resolved(data, dns); if(*dns) show_resolve_info(data, *dns); + if(result) + store_negative_resolve(data, data->state.async.hostname, + data->state.async.port); return result; } #endif diff --git a/lib/http.c b/lib/http.c index 08daab6dc..758ee50de 100644 --- a/lib/http.c +++ b/lib/http.c @@ -1323,7 +1323,7 @@ CURLcode Curl_http_follow(struct Curl_easy *data, const char *newurl, data->info.wouldredirect = follow_url; if(reachedmax) { - failf(data, "Maximum (%ld) redirects followed", data->set.maxredirs); + failf(data, "Maximum (%d) redirects followed", data->set.maxredirs); return CURLE_TOO_MANY_REDIRECTS; } return CURLE_OK; @@ -1528,8 +1528,7 @@ CURLcode Curl_http_do_pollset(struct Curl_easy *data, struct easy_pollset *ps) { /* write mode */ - curl_socket_t sock = Curl_conn_get_socket(data, FIRSTSOCKET); - return Curl_pollset_add_out(data, ps, sock); + return Curl_pollset_add_out(data, ps, data->conn->sock[FIRSTSOCKET]); } /* @@ -2415,7 +2414,7 @@ static CURLcode http_req_complete(struct Curl_easy *data, out: if(!result) { /* setup variables for the upcoming transfer */ - Curl_xfer_setup1(data, CURL_XFER_SENDRECV, -1, TRUE); + Curl_xfer_setup_sendrecv(data, FIRSTSOCKET, -1); } return result; } @@ -2704,6 +2703,8 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) if(result) goto fail; info_version = "HTTP/2"; + /* There is no ALPN here, but the connection is now definitely h2 */ + conn->httpversion_seen = 20; } else info_version = "HTTP/1.x"; @@ -4785,7 +4786,7 @@ static CURLcode cr_exp100_read(struct Curl_easy *data, /* We are now waiting for a reply from the server or * a timeout on our side IFF the request has been fully sent. */ DEBUGF(infof(data, "cr_exp100_read, start AWAITING_CONTINUE, " - "timeout %ldms", data->set.expect_100_timeout)); + "timeout %dms", data->set.expect_100_timeout)); ctx->state = EXP100_AWAITING_CONTINUE; ctx->start = curlx_now(); Curl_expire(data, data->set.expect_100_timeout, EXPIRE_100_TIMEOUT); diff --git a/lib/imap.c b/lib/imap.c index 5949b667e..7e6b132ba 100644 --- a/lib/imap.c +++ b/lib/imap.c @@ -1347,7 +1347,7 @@ static CURLcode imap_state_fetch_resp(struct Curl_easy *data, else { /* IMAP download */ data->req.maxdownload = size; - Curl_xfer_setup1(data, CURL_XFER_RECV, size, FALSE); + Curl_xfer_setup_recv(data, FIRSTSOCKET, size); } } else { @@ -1398,7 +1398,7 @@ static CURLcode imap_state_append_resp(struct Curl_easy *data, Curl_pgrsSetUploadSize(data, data->state.infilesize); /* IMAP upload */ - Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE); + Curl_xfer_setup_send(data, FIRSTSOCKET); /* End of DO phase */ imap_state(data, imapc, IMAP_STOP); diff --git a/lib/multi.c b/lib/multi.c index 9a653cf95..d38155cd9 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -912,7 +912,7 @@ static CURLcode mstate_connecting_pollset(struct Curl_easy *data, struct easy_pollset *ps) { if(data->conn) { - curl_socket_t sockfd = Curl_conn_get_socket(data, FIRSTSOCKET); + curl_socket_t sockfd = Curl_conn_get_first_socket(data); if(sockfd != CURL_SOCKET_BAD) { /* Default is to wait to something from the server */ return Curl_pollset_change(data, ps, sockfd, CURL_POLL_IN, 0); @@ -928,7 +928,7 @@ static CURLcode mstate_protocol_pollset(struct Curl_easy *data, curl_socket_t sockfd; if(data->conn->handler->proto_pollset) return data->conn->handler->proto_pollset(data, ps); - sockfd = Curl_conn_get_socket(data, FIRSTSOCKET); + sockfd = data->conn->sock[FIRSTSOCKET]; if(sockfd != CURL_SOCKET_BAD) { /* Default is to wait to something from the server */ return Curl_pollset_change(data, ps, sockfd, CURL_POLL_IN, 0); @@ -940,13 +940,13 @@ static CURLcode mstate_protocol_pollset(struct Curl_easy *data, static CURLcode mstate_do_pollset(struct Curl_easy *data, struct easy_pollset *ps) { - struct connectdata *conn = data->conn; if(data->conn) { if(data->conn->handler->doing_pollset) return data->conn->handler->doing_pollset(data, ps); - else if(conn->sockfd != CURL_SOCKET_BAD) { + else if(CONN_SOCK_IDX_VALID(data->conn->send_idx)) { /* Default is that we want to send something to the server */ - return Curl_pollset_add_out(data, ps, conn->sockfd); + return Curl_pollset_add_out( + data, ps, data->conn->sock[data->conn->send_idx]); } } return CURLE_OK; @@ -958,9 +958,10 @@ static CURLcode mstate_domore_pollset(struct Curl_easy *data, if(data->conn) { if(data->conn->handler->domore_pollset) return data->conn->handler->domore_pollset(data, ps); - else if(data->conn->sockfd != CURL_SOCKET_BAD) { + else if(CONN_SOCK_IDX_VALID(data->conn->send_idx)) { /* Default is that we want to send something to the server */ - return Curl_pollset_add_out(data, ps, data->conn->sockfd); + return Curl_pollset_add_out( + data, ps, data->conn->sock[data->conn->send_idx]); } } return CURLE_OK; @@ -976,14 +977,15 @@ static CURLcode mstate_perform_pollset(struct Curl_easy *data, else { /* Default is to obey the data->req.keepon flags for send/recv */ CURLcode result = CURLE_OK; - if(CURL_WANT_RECV(data)) { - DEBUGASSERT(data->conn->sockfd != CURL_SOCKET_BAD); - result = Curl_pollset_add_in(data, ps, data->conn->sockfd); + if(CURL_WANT_RECV(data) && CONN_SOCK_IDX_VALID(data->conn->recv_idx)) { + result = Curl_pollset_add_in( + data, ps, data->conn->sock[data->conn->recv_idx]); } - if(!result && Curl_req_want_send(data)) { - DEBUGASSERT(data->conn->writesockfd != CURL_SOCKET_BAD); - result = Curl_pollset_add_out(data, ps, data->conn->writesockfd); + if(!result && Curl_req_want_send(data) && + CONN_SOCK_IDX_VALID(data->conn->send_idx)) { + result = Curl_pollset_add_out( + data, ps, data->conn->sock[data->conn->send_idx]); } return result; } @@ -2555,8 +2557,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* Only perform the transfer if there is a good socket to work with. Having both BAD is a signal to skip immediately to DONE */ - if((data->conn->sockfd != CURL_SOCKET_BAD) || - (data->conn->writesockfd != CURL_SOCKET_BAD)) + if(CONN_SOCK_IDX_VALID(data->conn->recv_idx) || + CONN_SOCK_IDX_VALID(data->conn->send_idx)) multistate(data, MSTATE_PERFORMING); else { #ifndef CURL_DISABLE_FTP @@ -2791,16 +2793,15 @@ CURLMcode curl_multi_perform(CURLM *m, int *running_handles) if(t) { /* the removed may have another timeout in queue */ struct Curl_easy *data = Curl_splayget(t); + (void)add_next_timeout(now, multi, data); if(data->mstate == MSTATE_PENDING) { bool stream_unused; CURLcode result_unused; if(multi_handle_timeout(data, &now, &stream_unused, &result_unused)) { infof(data, "PENDING handle timeout"); move_pending_to_connect(multi, data); - continue; } } - (void)add_next_timeout(now, multi, Curl_splayget(t)); } } while(t); @@ -3244,13 +3245,13 @@ CURLMcode curl_multi_setopt(CURLM *m, } break; case CURLMOPT_NETWORK_CHANGED: { - long val = va_arg(param, long); - if(val & CURLM_NWCOPT_CLEAR_DNS) { - Curl_dnscache_clear(multi->admin); - } - if(val & CURLM_NWCOPT_CLEAR_CONNS) { - Curl_cpool_nw_changed(multi->admin); - } + long val = va_arg(param, long); + if(val & CURLMNWC_CLEAR_DNS) { + Curl_dnscache_clear(multi->admin); + } + if(val & CURLMNWC_CLEAR_CONNS) { + Curl_cpool_nw_changed(multi->admin); + } break; } default: diff --git a/lib/openldap.c b/lib/openldap.c index c532be3f3..1b32e12b6 100644 --- a/lib/openldap.c +++ b/lib/openldap.c @@ -993,7 +993,7 @@ static CURLcode oldap_do(struct Curl_easy *data, bool *done) } lr->msgid = msgid; - Curl_xfer_setup1(data, CURL_XFER_RECV, -1, FALSE); + Curl_xfer_setup_recv(data, FIRSTSOCKET, -1); *done = TRUE; out: diff --git a/lib/pop3.c b/lib/pop3.c index 493b36f45..508f8faed 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -1116,7 +1116,7 @@ static CURLcode pop3_state_command_resp(struct Curl_easy *data, if(pop3->transfer == PPTRANSFER_BODY) { /* POP3 download */ - Curl_xfer_setup1(data, CURL_XFER_RECV, -1, FALSE); + Curl_xfer_setup_recv(data, FIRSTSOCKET, -1); if(pp->overflow) { /* The recv buffer contains data that is actually body content so send diff --git a/lib/request.c b/lib/request.c index 9fc9ab4d6..733e3e929 100644 --- a/lib/request.c +++ b/lib/request.c @@ -62,7 +62,7 @@ CURLcode Curl_req_soft_reset(struct SingleRequest *req, req->shutdown = FALSE; req->bytecount = 0; req->writebytecount = 0; - req->header = TRUE; /* assume header */ + req->header = FALSE; req->headerline = 0; req->headerbytecount = 0; req->allheadercount = 0; @@ -153,6 +153,7 @@ void Curl_req_hard_reset(struct SingleRequest *req, struct Curl_easy *data) req->eos_written = FALSE; req->eos_read = FALSE; req->eos_sent = FALSE; + req->rewind_read = FALSE; req->upload_done = FALSE; req->upload_aborted = FALSE; req->ignorebody = FALSE; @@ -160,7 +161,6 @@ void Curl_req_hard_reset(struct SingleRequest *req, struct Curl_easy *data) req->chunk = FALSE; req->ignore_cl = FALSE; req->upload_chunky = FALSE; - req->getheader = FALSE; req->no_body = data->set.opt_no_body; req->authneg = FALSE; req->shutdown = FALSE; diff --git a/lib/request.h b/lib/request.h index 74d9f5343..bce34de8b 100644 --- a/lib/request.h +++ b/lib/request.h @@ -123,7 +123,6 @@ struct SingleRequest { 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(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, diff --git a/lib/rtsp.c b/lib/rtsp.c index 46ff660ae..dbe3e63cf 100644 --- a/lib/rtsp.c +++ b/lib/rtsp.c @@ -100,6 +100,10 @@ static CURLcode rtsp_rtp_write_resp(struct Curl_easy *data, const char *buf, size_t blen, bool is_eos); +static CURLcode rtsp_rtp_write_resp_hd(struct Curl_easy *data, + const char *buf, + size_t blen, + bool is_eos); static CURLcode rtsp_setup_connection(struct Curl_easy *data, struct connectdata *conn); @@ -141,7 +145,7 @@ const struct Curl_handler Curl_handler_rtsp = { ZERO_NULL, /* perform_pollset */ ZERO_NULL, /* disconnect */ rtsp_rtp_write_resp, /* write_resp */ - ZERO_NULL, /* write_resp_hd */ + rtsp_rtp_write_resp_hd, /* write_resp_hd */ rtsp_conncheck, /* connection_check */ ZERO_NULL, /* attach connection */ Curl_http_follow, /* follow */ @@ -370,7 +374,7 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done) } if(rtspreq == RTSPREQ_RECEIVE) { - Curl_xfer_setup1(data, CURL_XFER_RECV, -1, TRUE); + Curl_xfer_setup_recv(data, FIRSTSOCKET, -1); goto out; } @@ -636,7 +640,7 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done) if(result) goto out; - Curl_xfer_setup1(data, CURL_XFER_SENDRECV, -1, TRUE); + Curl_xfer_setup_sendrecv(data, FIRSTSOCKET, -1); /* issue the request */ result = Curl_req_send(data, &req_buffer, httpversion); @@ -935,6 +939,14 @@ out: return result; } +static CURLcode rtsp_rtp_write_resp_hd(struct Curl_easy *data, + const char *buf, + size_t blen, + bool is_eos) +{ + return rtsp_rtp_write_resp(data, buf, blen, is_eos); +} + static CURLcode rtp_client_write(struct Curl_easy *data, const char *ptr, size_t len) { diff --git a/lib/setopt.c b/lib/setopt.c index 394b5567e..168417738 100644 --- a/lib/setopt.c +++ b/lib/setopt.c @@ -60,7 +60,6 @@ #include "curl_memory.h" #include "memdebug.h" - static CURLcode setopt_set_timeout_sec(timediff_t *ptimeout_ms, long secs) { if(secs < 0) @@ -854,6 +853,17 @@ static CURLcode setopt_bool(struct Curl_easy *data, CURLoption option, return CURLE_OK; } +static CURLcode value_range(long *value, long below_error, long min, long max) +{ + if(*value < below_error) + return CURLE_BAD_FUNCTION_ARGUMENT; + else if(*value < min) + *value = min; + else if(*value > max) + *value = max; + return CURLE_OK; +} + static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, long arg) { @@ -866,21 +876,13 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, switch(option) { case CURLOPT_DNS_CACHE_TIMEOUT: - if(arg < -1) - return CURLE_BAD_FUNCTION_ARGUMENT; - else if(arg > INT_MAX/1000) - arg = INT_MAX/1000; + return setopt_set_timeout_sec(&s->dns_cache_timeout_ms, arg); - if(arg > 0) - arg *= 1000; - s->dns_cache_timeout_ms = (int)arg; - break; case CURLOPT_CA_CACHE_TIMEOUT: if(Curl_ssl_supports(data, SSLSUPP_CA_CACHE)) { - if(arg < -1) - return CURLE_BAD_FUNCTION_ARGUMENT; - else if(arg > INT_MAX) - arg = INT_MAX; + result = value_range(&arg, -1, -1, INT_MAX); + if(result) + return result; s->general_ssl.ca_cache_timeout = (int)arg; } @@ -888,64 +890,38 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, return CURLE_NOT_BUILT_IN; break; case CURLOPT_MAXCONNECTS: - /* - * Set the absolute number of maximum simultaneous alive connection that - * libcurl is allowed to have. - */ - if(uarg > UINT_MAX) - return CURLE_BAD_FUNCTION_ARGUMENT; - s->maxconnects = (unsigned int)uarg; + result = value_range(&arg, 1, 1, UINT_MAX); + if(result) + return result; + s->maxconnects = (unsigned int)arg; break; case CURLOPT_SERVER_RESPONSE_TIMEOUT: - /* - * Option that specifies how quickly a server response must be obtained - * before it is considered failure. For pingpong protocols. - */ return setopt_set_timeout_sec(&s->server_response_timeout, arg); case CURLOPT_SERVER_RESPONSE_TIMEOUT_MS: - /* - * Option that specifies how quickly a server response must be obtained - * before it is considered failure. For pingpong protocols. - */ return setopt_set_timeout_ms(&s->server_response_timeout, arg); #ifndef CURL_DISABLE_TFTP case CURLOPT_TFTP_BLKSIZE: - /* - * TFTP option that specifies the block size to use for data transmission. - */ - if(arg < TFTP_BLKSIZE_MIN) - arg = 512; - else if(arg > TFTP_BLKSIZE_MAX) - arg = TFTP_BLKSIZE_MAX; - s->tftp_blksize = arg; + result = value_range(&arg, 0, TFTP_BLKSIZE_MIN, TFTP_BLKSIZE_MAX); + if(result) + return result; + s->tftp_blksize = (unsigned short)arg; break; #endif #ifndef CURL_DISABLE_NETRC case CURLOPT_NETRC: - /* - * Parse the $HOME/.netrc file - */ if((arg < CURL_NETRC_IGNORED) || (arg >= CURL_NETRC_LAST)) return CURLE_BAD_FUNCTION_ARGUMENT; s->use_netrc = (unsigned char)arg; break; #endif case CURLOPT_TIMECONDITION: - /* - * Set HTTP time condition. This must be one of the defines in the - * curl/curl.h header file. - */ if((arg < CURL_TIMECOND_NONE) || (arg >= CURL_TIMECOND_LAST)) return CURLE_BAD_FUNCTION_ARGUMENT; s->timecondition = (unsigned char)arg; break; case CURLOPT_TIMEVALUE: - /* - * This is the value to compare with the remote document with the - * method set with CURLOPT_TIMECONDITION - */ s->timevalue = (time_t)arg; break; case CURLOPT_SSLVERSION: @@ -955,10 +931,6 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, return Curl_setopt_SSLVERSION(data, option, arg); case CURLOPT_POSTFIELDSIZE: - /* - * The size of the POSTFIELD data to prevent libcurl to do strlen() to - * figure it out. Enables binary posts. - */ if(arg < -1) return CURLE_BAD_FUNCTION_ARGUMENT; @@ -973,34 +945,19 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, break; #ifndef CURL_DISABLE_HTTP case CURLOPT_FOLLOWLOCATION: - /* - * Follow Location: header hints on an HTTP-server. - */ if(uarg > 3) return CURLE_BAD_FUNCTION_ARGUMENT; s->http_follow_mode = (unsigned char)uarg; break; case CURLOPT_MAXREDIRS: - /* - * The maximum amount of hops you allow curl to follow Location: - * headers. This should mostly be used to detect never-ending loops. - */ - if(arg < -1) - return CURLE_BAD_FUNCTION_ARGUMENT; - s->maxredirs = arg; + result = value_range(&arg, -1, 0, 0x7fff); + if(result) + return result; + s->maxredirs = (short)arg; break; case CURLOPT_POSTREDIR: - /* - * Set the behavior of POST when redirecting - * CURL_REDIR_GET_ALL - POST is changed to GET after 301 and 302 - * CURL_REDIR_POST_301 - POST is kept as POST after 301 - * CURL_REDIR_POST_302 - POST is kept as POST after 302 - * CURL_REDIR_POST_303 - POST is kept as POST after 303 - * CURL_REDIR_POST_ALL - POST is kept as POST after 301, 302 and 303 - * other - POST is kept as POST after 301 and 302 - */ if(arg < CURL_REDIR_GET_ALL) /* no return error on too high numbers since the bitmask could be extended in a future */ @@ -1009,9 +966,6 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, break; case CURLOPT_HEADEROPT: - /* - * Set header option. - */ s->sep_headers = !!(arg & CURLHEADER_SEPARATE); break; case CURLOPT_HTTPAUTH: @@ -1021,13 +975,10 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, return setopt_HTTP_VERSION(data, arg); case CURLOPT_EXPECT_100_TIMEOUT_MS: - /* - * Time to wait for a response to an HTTP request containing an - * Expect: 100-continue header before sending the data anyway. - */ - if(arg < 0) - return CURLE_BAD_FUNCTION_ARGUMENT; - s->expect_100_timeout = arg; + result = value_range(&arg, 0, 0, 0xffff); + if(result) + return result; + s->expect_100_timeout = (unsigned short)arg; break; #endif /* ! CURL_DISABLE_HTTP */ @@ -1039,9 +990,6 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, #endif #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXYPORT: - /* - * Explicitly set HTTP proxy port number. - */ if((arg < 0) || (arg > 65535)) return CURLE_BAD_FUNCTION_ARGUMENT; s->proxyport = (unsigned short)arg; @@ -1051,9 +999,6 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, return httpauth(data, TRUE, uarg); case CURLOPT_PROXYTYPE: - /* - * Set proxy type. - */ if((arg < CURLPROXY_HTTP) || (arg > CURLPROXY_SOCKS5_HOSTNAME)) return CURLE_BAD_FUNCTION_ARGUMENT; s->proxytype = (unsigned char)arg; @@ -1068,9 +1013,6 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, #ifndef CURL_DISABLE_FTP case CURLOPT_FTP_FILEMETHOD: - /* - * How do access files over FTP. - */ if((arg < CURLFTPMETHOD_DEFAULT) || (arg >= CURLFTPMETHOD_LAST)) return CURLE_BAD_FUNCTION_ARGUMENT; s->ftp_filemethod = (unsigned char)arg; @@ -1082,89 +1024,53 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, break; case CURLOPT_FTPSSLAUTH: - /* - * Set a specific auth for FTP-SSL transfers. - */ if((arg < CURLFTPAUTH_DEFAULT) || (arg >= CURLFTPAUTH_LAST)) return CURLE_BAD_FUNCTION_ARGUMENT; s->ftpsslauth = (unsigned char)arg; break; case CURLOPT_ACCEPTTIMEOUT_MS: - /* - * The maximum time for curl to wait for FTP server connect - */ return setopt_set_timeout_ms(&s->accepttimeout, arg); #endif /* ! CURL_DISABLE_FTP */ #if !defined(CURL_DISABLE_FTP) || defined(USE_SSH) case CURLOPT_FTP_CREATE_MISSING_DIRS: - /* - * An FTP/SFTP option that modifies an upload to create missing - * directories on the server. - */ - /* reserve other values for future use */ if((arg < CURLFTP_CREATE_DIR_NONE) || (arg > CURLFTP_CREATE_DIR_RETRY)) return CURLE_BAD_FUNCTION_ARGUMENT; s->ftp_create_missing_dirs = (unsigned char)arg; break; #endif /* ! CURL_DISABLE_FTP || USE_SSH */ case CURLOPT_INFILESIZE: - /* - * If known, this should inform curl about the file size of the - * to-be-uploaded file. - */ if(arg < -1) return CURLE_BAD_FUNCTION_ARGUMENT; s->filesize = arg; break; case CURLOPT_LOW_SPEED_LIMIT: - /* - * The low speed limit that if transfers are below this for - * CURLOPT_LOW_SPEED_TIME, the transfer is aborted. - */ if(arg < 0) return CURLE_BAD_FUNCTION_ARGUMENT; s->low_speed_limit = arg; break; case CURLOPT_LOW_SPEED_TIME: - /* - * The low speed time that if transfers are below the set - * CURLOPT_LOW_SPEED_LIMIT during this time, the transfer is aborted. - */ if(arg < 0) return CURLE_BAD_FUNCTION_ARGUMENT; s->low_speed_time = arg; break; case CURLOPT_PORT: - /* - * The port number to use when getting the URL. 0 disables it. - */ if((arg < 0) || (arg > 65535)) return CURLE_BAD_FUNCTION_ARGUMENT; s->use_port = (unsigned short)arg; break; case CURLOPT_TIMEOUT: - /* - * The maximum time you allow curl to use for a single transfer - * operation. - */ return setopt_set_timeout_sec(&s->timeout, arg); case CURLOPT_TIMEOUT_MS: return setopt_set_timeout_ms(&s->timeout, arg); case CURLOPT_CONNECTTIMEOUT: - /* - * The maximum time you allow curl to use to connect. - */ return setopt_set_timeout_sec(&s->connecttimeout, arg); case CURLOPT_CONNECTTIMEOUT_MS: return setopt_set_timeout_ms(&s->connecttimeout, arg); case CURLOPT_RESUME_FROM: - /* - * Resume transfer at the given file position - */ if(arg < -1) return CURLE_BAD_FUNCTION_ARGUMENT; s->set_resume_from = arg; @@ -1172,17 +1078,11 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, #ifndef CURL_DISABLE_BINDLOCAL case CURLOPT_LOCALPORT: - /* - * Set what local port to bind the socket to when performing an operation. - */ if((arg < 0) || (arg > 65535)) return CURLE_BAD_FUNCTION_ARGUMENT; s->localport = curlx_sltous(arg); break; case CURLOPT_LOCALPORTRANGE: - /* - * Set number of local ports to try, starting with CURLOPT_LOCALPORT. - */ if((arg < 0) || (arg > 65535)) return CURLE_BAD_FUNCTION_ARGUMENT; s->localportrange = curlx_sltous(arg); @@ -1191,51 +1091,28 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, #ifdef HAVE_GSSAPI case CURLOPT_GSSAPI_DELEGATION: - /* - * GSS-API credential delegation bitmask - */ s->gssapi_delegation = (unsigned char)uarg& (CURLGSSAPI_DELEGATION_POLICY_FLAG|CURLGSSAPI_DELEGATION_FLAG); break; #endif case CURLOPT_SSL_FALSESTART: - /* - * No TLS backends support false start anymore. - */ return CURLE_NOT_BUILT_IN; case CURLOPT_BUFFERSIZE: - /* - * The application kindly asks for a differently sized receive buffer. - * If it seems reasonable, we will use it. - */ - if(arg > READBUFFER_MAX) - arg = READBUFFER_MAX; - else if(arg < 1) - arg = READBUFFER_SIZE; - else if(arg < READBUFFER_MIN) - arg = READBUFFER_MIN; - + result = value_range(&arg, 0, READBUFFER_MIN, READBUFFER_MAX); + if(result) + return result; s->buffer_size = (unsigned int)arg; break; case CURLOPT_UPLOAD_BUFFERSIZE: - /* - * The application kindly asks for a differently sized upload buffer. - * Cap it to sensible. - */ - if(arg > UPLOADBUFFER_MAX) - arg = UPLOADBUFFER_MAX; - else if(arg < UPLOADBUFFER_MIN) - arg = UPLOADBUFFER_MIN; - + result = value_range(&arg, 0, UPLOADBUFFER_MIN, UPLOADBUFFER_MAX); + if(result) + return result; s->upload_buffer_size = (unsigned int)arg; break; case CURLOPT_MAXFILESIZE: - /* - * Set the maximum size of a file to download. - */ if(arg < 0) return CURLE_BAD_FUNCTION_ARGUMENT; s->max_filesize = arg; @@ -1243,9 +1120,6 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, #ifdef USE_SSL case CURLOPT_USE_SSL: - /* - * Make transfers attempt to use SSL/TLS. - */ if((arg < CURLUSESSL_NONE) || (arg >= CURLUSESSL_LAST)) return CURLE_BAD_FUNCTION_ARGUMENT; s->use_ssl = (unsigned char)arg; @@ -1268,12 +1142,7 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, break; case CURLOPT_CONNECT_ONLY: - /* - * No data transfer. - * (1) - only do connection - * (2) - do first get request but get no content - */ - if(arg > 2) + if(arg < 0 || arg > 2) return CURLE_BAD_FUNCTION_ARGUMENT; s->connect_only = !!arg; s->connect_only_ws = (arg == 2); @@ -1281,7 +1150,6 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, #ifdef USE_SSH - /* we only include SSH options if explicitly built to support SSH */ case CURLOPT_SSH_AUTH_TYPES: s->ssh_auth_types = (int)arg; break; @@ -1289,9 +1157,6 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, #if !defined(CURL_DISABLE_FTP) || defined(USE_SSH) case CURLOPT_NEW_FILE_PERMS: - /* - * Uses these permissions instead of 0644 - */ if((arg < 0) || (arg > 0777)) return CURLE_BAD_FUNCTION_ARGUMENT; s->new_file_perms = (unsigned int)arg; @@ -1299,9 +1164,6 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, #endif #ifdef USE_SSH case CURLOPT_NEW_DIRECTORY_PERMS: - /* - * Uses these permissions instead of 0755 - */ if((arg < 0) || (arg > 0777)) return CURLE_BAD_FUNCTION_ARGUMENT; s->new_directory_perms = (unsigned int)arg; @@ -1309,11 +1171,6 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, #endif #ifdef USE_IPV6 case CURLOPT_ADDRESS_SCOPE: - /* - * Use this scope id when using IPv6 - * We always get longs when passed plain numericals so we should check - * that the value fits into an unsigned 32-bit integer. - */ #if SIZEOF_LONG > 4 if(uarg > UINT_MAX) return CURLE_BAD_FUNCTION_ARGUMENT; @@ -1322,17 +1179,10 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, break; #endif case CURLOPT_PROTOCOLS: - /* set the bitmask for the protocols that are allowed to be used for the - transfer, which thus helps the app which takes URLs from users or other - external inputs and want to restrict what protocol(s) to deal with. - Defaults to CURLPROTO_ALL. */ s->allowed_protocols = (curl_prot_t)arg; break; case CURLOPT_REDIR_PROTOCOLS: - /* set the bitmask for the protocols that libcurl is allowed to follow to, - as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol - needs to be set in both bitmasks to be allowed to get redirected to. */ s->redir_protocols = (curl_prot_t)arg; break; @@ -1340,40 +1190,31 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, case CURLOPT_RTSP_REQUEST: return setopt_RTSP_REQUEST(data, arg); case CURLOPT_RTSP_CLIENT_CSEQ: - /* - * Set the CSEQ number to issue for the next RTSP request. Useful if the - * application is resuming a previously broken connection. The CSEQ - * will increment from this new number henceforth. - */ data->state.rtsp_next_client_CSeq = arg; break; case CURLOPT_RTSP_SERVER_CSEQ: - /* Same as the above, but for server-initiated requests */ data->state.rtsp_next_server_CSeq = arg; break; #endif /* ! CURL_DISABLE_RTSP */ case CURLOPT_TCP_KEEPIDLE: - if(arg < 0) - return CURLE_BAD_FUNCTION_ARGUMENT; - else if(arg > INT_MAX) - arg = INT_MAX; + result = value_range(&arg, 0, 0, INT_MAX); + if(result) + return result; s->tcp_keepidle = (int)arg; break; case CURLOPT_TCP_KEEPINTVL: - if(arg < 0) - return CURLE_BAD_FUNCTION_ARGUMENT; - else if(arg > INT_MAX) - arg = INT_MAX; + result = value_range(&arg, 0, 0, INT_MAX); + if(result) + return result; s->tcp_keepintvl = (int)arg; break; case CURLOPT_TCP_KEEPCNT: - if(arg < 0) - return CURLE_BAD_FUNCTION_ARGUMENT; - else if(arg > INT_MAX) - arg = INT_MAX; + result = value_range(&arg, 0, 0, INT_MAX); + if(result) + return result; s->tcp_keepcnt = (int)arg; break; case CURLOPT_SSL_ENABLE_NPN: @@ -1436,16 +1277,12 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, /* deprecated */ break; case CURLOPT_SSLENGINE_DEFAULT: - /* - * flag to set engine as default. - */ Curl_safefree(s->str[STRING_SSL_ENGINE]); return Curl_ssl_set_engine_default(data); case CURLOPT_UPLOAD_FLAGS: s->upload_flags = (unsigned char)arg; break; default: - /* unknown option */ return CURLE_UNKNOWN_OPTION; } return CURLE_OK; diff --git a/lib/smtp.c b/lib/smtp.c index 4bb3bde4a..97083e41f 100644 --- a/lib/smtp.c +++ b/lib/smtp.c @@ -1257,7 +1257,7 @@ static CURLcode smtp_state_data_resp(struct Curl_easy *data, Curl_pgrsSetUploadSize(data, data->state.infilesize); /* SMTP upload */ - Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE); + Curl_xfer_setup_send(data, FIRSTSOCKET); /* End of DO phase */ smtp_state(data, smtpc, SMTP_STOP); diff --git a/lib/splay.c b/lib/splay.c index 609b799bf..3ca8678b2 100644 --- a/lib/splay.c +++ b/lib/splay.c @@ -223,6 +223,7 @@ int Curl_splayremove(struct Curl_tree *t, if(compare(SPLAY_SUBNODE, removenode->key) == 0) { /* It is a subnode within a 'same' linked list and thus we can unlink it easily. */ + DEBUGASSERT(removenode->samen != removenode); if(removenode->samen == removenode) /* A non-subnode should never be set to SPLAY_SUBNODE */ return 3; diff --git a/lib/transfer.c b/lib/transfer.c index 84e4c5e92..50f621056 100644 --- a/lib/transfer.c +++ b/lib/transfer.c @@ -162,38 +162,23 @@ bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc) static CURLcode xfer_recv_shutdown(struct Curl_easy *data, bool *done) { - int sockindex; - if(!data || !data->conn) return CURLE_FAILED_INIT; - if(data->conn->sockfd == CURL_SOCKET_BAD) - return CURLE_FAILED_INIT; - sockindex = (data->conn->sockfd == data->conn->sock[SECONDARYSOCKET]); - return Curl_conn_shutdown(data, sockindex, done); + return Curl_conn_shutdown(data, data->conn->recv_idx, done); } static bool xfer_recv_shutdown_started(struct Curl_easy *data) { - int sockindex; - if(!data || !data->conn) return FALSE; - if(data->conn->sockfd == CURL_SOCKET_BAD) - return FALSE; - sockindex = (data->conn->sockfd == data->conn->sock[SECONDARYSOCKET]); - return Curl_shutdown_started(data, sockindex); + return Curl_shutdown_started(data, data->conn->recv_idx); } CURLcode Curl_xfer_send_shutdown(struct Curl_easy *data, bool *done) { - int sockindex; - if(!data || !data->conn) return CURLE_FAILED_INIT; - if(data->conn->writesockfd == CURL_SOCKET_BAD) - return CURLE_FAILED_INIT; - sockindex = (data->conn->writesockfd == data->conn->sock[SECONDARYSOCKET]); - return Curl_conn_shutdown(data, sockindex, done); + return Curl_conn_shutdown(data, data->conn->send_idx, done); } /** @@ -732,101 +717,88 @@ CURLcode Curl_retry_request(struct Curl_easy *data, char **url) return CURLE_OK; } -/* - * xfer_setup() is called to setup basic properties for the transfer. - */ static void 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 */ - bool getheader, /* TRUE if header parsing is wanted */ - int writesockindex, /* socket index to write to, it may be the same we - read from. -1 disables */ - bool shutdown, /* shutdown connection at transfer end. Only - * supported when sending OR receiving. */ - bool shutdown_err_ignore /* errors during shutdown do not fail the - * transfer */ + int send_idx, /* sockindex to send on or -1 */ + int recv_idx, /* sockindex to receive on or -1 */ + curl_off_t recv_size /* how much to receive, -1 if unknown */ ) { struct SingleRequest *k = &data->req; struct connectdata *conn = data->conn; - bool want_send = Curl_req_want_send(data); DEBUGASSERT(conn != NULL); - DEBUGASSERT((sockindex <= 1) && (sockindex >= -1)); - DEBUGASSERT((writesockindex <= 1) && (writesockindex >= -1)); - DEBUGASSERT(!shutdown || (sockindex == -1) || (writesockindex == -1)); - - if(Curl_conn_is_multiplex(conn, FIRSTSOCKET) || want_send) { - /* when multiplexing, the read/write sockets need to be the same! */ - conn->sockfd = sockindex == -1 ? - ((writesockindex == -1 ? CURL_SOCKET_BAD : conn->sock[writesockindex])) : - conn->sock[sockindex]; - conn->writesockfd = conn->sockfd; - if(want_send) - /* special and HTTP-specific */ - writesockindex = FIRSTSOCKET; - } - else { - conn->sockfd = sockindex == -1 ? - CURL_SOCKET_BAD : conn->sock[sockindex]; - conn->writesockfd = writesockindex == -1 ? - CURL_SOCKET_BAD : conn->sock[writesockindex]; - } - - k->getheader = getheader; - k->size = size; - k->shutdown = shutdown; - k->shutdown_err_ignore = shutdown_err_ignore; + /* indexes are in range */ + DEBUGASSERT((send_idx <= 1) && (send_idx >= -1)); + DEBUGASSERT((recv_idx <= 1) && (recv_idx >= -1)); + /* if request wants to send, switching off the send direction is wrong */ + DEBUGASSERT((send_idx >= 0) || !Curl_req_want_send(data)); + + conn->send_idx = send_idx; + conn->recv_idx = recv_idx; + + /* without receiving, there should be not recv_size */ + DEBUGASSERT((conn->recv_idx >= 0) || (recv_size == -1)); + k->size = recv_size; + k->header = !!conn->handler->write_resp_hd; + /* by default, we do not shutdown at the end of the transfer */ + k->shutdown = FALSE; + k->shutdown_err_ignore = FALSE; /* The code sequence below is placed in this function just because all necessary input is not always known in do_complete() as this function may be called after that */ + if(!k->header && (recv_size > 0)) + Curl_pgrsSetDownloadSize(data, recv_size); - if(!k->getheader) { - k->header = FALSE; - if(size > 0) - Curl_pgrsSetDownloadSize(data, size); - } /* we want header and/or body, if neither then do not do this! */ - if(k->getheader || !data->req.no_body) { + if(conn->handler->write_resp_hd || !data->req.no_body) { - if(sockindex != -1) + if(conn->recv_idx != -1) k->keepon |= KEEP_RECV; - if(writesockindex != -1) + if(conn->send_idx != -1) k->keepon |= KEEP_SEND; - } /* if(k->getheader || !data->req.no_body) */ + } + CURL_TRC_M(data, "xfer_setup: recv_idx=%d, send_idx=%d", + conn->recv_idx, conn->send_idx); } void Curl_xfer_setup_nop(struct Curl_easy *data) { - xfer_setup(data, -1, -1, FALSE, -1, FALSE, FALSE); + xfer_setup(data, -1, -1, -1); +} + +void Curl_xfer_setup_sendrecv(struct Curl_easy *data, + int sockindex, + curl_off_t recv_size) +{ + xfer_setup(data, sockindex, sockindex, recv_size); } -void Curl_xfer_setup1(struct Curl_easy *data, - int send_recv, - curl_off_t recv_size, - bool getheader) +void Curl_xfer_setup_send(struct Curl_easy *data, + int sockindex) { - int recv_index = (send_recv & CURL_XFER_RECV) ? FIRSTSOCKET : -1; - int send_index = (send_recv & CURL_XFER_SEND) ? FIRSTSOCKET : -1; - DEBUGASSERT((recv_index >= 0) || (recv_size == -1)); - xfer_setup(data, recv_index, recv_size, getheader, send_index, FALSE, FALSE); + xfer_setup(data, sockindex, -1, -1); } -void Curl_xfer_setup2(struct Curl_easy *data, - int send_recv, - curl_off_t recv_size, - bool shutdown, - bool shutdown_err_ignore) +void Curl_xfer_setup_recv(struct Curl_easy *data, + int sockindex, + curl_off_t recv_size) { - int recv_index = (send_recv & CURL_XFER_RECV) ? SECONDARYSOCKET : -1; - int send_index = (send_recv & CURL_XFER_SEND) ? SECONDARYSOCKET : -1; - DEBUGASSERT((recv_index >= 0) || (recv_size == -1)); - xfer_setup(data, recv_index, recv_size, FALSE, send_index, - shutdown, shutdown_err_ignore); + xfer_setup(data, -1, sockindex, recv_size); +} + +void Curl_xfer_set_shutdown(struct Curl_easy *data, + bool shutdown, + bool ignore_errors) +{ + /* Shutdown should only be set when the transfer only sends or receives. */ + DEBUGASSERT(!shutdown || + (data->conn->send_idx < 0) || (data->conn->recv_idx < 0)); + data->req.shutdown = shutdown; + data->req.shutdown_err_ignore = ignore_errors; } CURLcode Curl_xfer_write_resp(struct Curl_easy *data, @@ -886,18 +858,12 @@ CURLcode Curl_xfer_write_done(struct Curl_easy *data, bool premature) bool Curl_xfer_needs_flush(struct Curl_easy *data) { - int sockindex; - sockindex = ((data->conn->writesockfd != CURL_SOCKET_BAD) && - (data->conn->writesockfd == data->conn->sock[SECONDARYSOCKET])); - return Curl_conn_needs_flush(data, sockindex); + return Curl_conn_needs_flush(data, data->conn->send_idx); } CURLcode Curl_xfer_flush(struct Curl_easy *data) { - int sockindex; - sockindex = ((data->conn->writesockfd != CURL_SOCKET_BAD) && - (data->conn->writesockfd == data->conn->sock[SECONDARYSOCKET])); - return Curl_conn_flush(data, sockindex); + return Curl_conn_flush(data, data->conn->send_idx); } CURLcode Curl_xfer_send(struct Curl_easy *data, @@ -905,14 +871,12 @@ CURLcode Curl_xfer_send(struct Curl_easy *data, size_t *pnwritten) { CURLcode result; - int sockindex; DEBUGASSERT(data); DEBUGASSERT(data->conn); - sockindex = ((data->conn->writesockfd != CURL_SOCKET_BAD) && - (data->conn->writesockfd == data->conn->sock[SECONDARYSOCKET])); - result = Curl_conn_send(data, sockindex, buf, blen, eos, pnwritten); + result = Curl_conn_send(data, data->conn->send_idx, + buf, blen, eos, pnwritten); if(result == CURLE_AGAIN) { result = CURLE_OK; *pnwritten = 0; @@ -929,17 +893,13 @@ CURLcode Curl_xfer_recv(struct Curl_easy *data, char *buf, size_t blen, size_t *pnrcvd) { - int sockindex; - DEBUGASSERT(data); DEBUGASSERT(data->conn); DEBUGASSERT(data->set.buffer_size > 0); - sockindex = ((data->conn->sockfd != CURL_SOCKET_BAD) && - (data->conn->sockfd == data->conn->sock[SECONDARYSOCKET])); if((size_t)data->set.buffer_size < blen) blen = (size_t)data->set.buffer_size; - return Curl_conn_recv(data, sockindex, buf, blen, pnrcvd); + return Curl_conn_recv(data, data->conn->recv_idx, buf, blen, pnrcvd); } CURLcode Curl_xfer_send_close(struct Curl_easy *data) diff --git a/lib/transfer.h b/lib/transfer.h index 157c6b991..91a81e52e 100644 --- a/lib/transfer.h +++ b/lib/transfer.h @@ -64,38 +64,33 @@ bool Curl_xfer_write_is_paused(struct Curl_easy *data); CURLcode Curl_xfer_write_resp_hd(struct Curl_easy *data, const char *hd0, size_t hdlen, bool is_eos); -#define CURL_XFER_NOP (0) -#define CURL_XFER_RECV (1<<(0)) -#define CURL_XFER_SEND (1<<(1)) -#define CURL_XFER_SENDRECV (CURL_XFER_RECV|CURL_XFER_SEND) - -/** - * The transfer is neither receiving nor sending now. - */ +/* The transfer is neither receiving nor sending. */ void Curl_xfer_setup_nop(struct Curl_easy *data); -/** - * The transfer will use socket 1 to send/recv. `recv_size` is - * the amount to receive or -1 if unknown. `getheader` indicates - * response header processing is expected. - */ -void Curl_xfer_setup1(struct Curl_easy *data, - int send_recv, - curl_off_t recv_size, - bool getheader); +/* The transfer sends data on the given socket index */ +void Curl_xfer_setup_send(struct Curl_easy *data, + int sockindex); + +/* The transfer receives data on the given socket index, the + * amount to receive (or -1 if unknown). */ +void Curl_xfer_setup_recv(struct Curl_easy *data, + int sockindex, + curl_off_t recv_size); + +/* *After* Curl_xfer_setup_xxx(), tell the transfer to shutdown the + * connection at the end. Let the transfer either fail or ignore any + * errors during shutdown. */ +void Curl_xfer_set_shutdown(struct Curl_easy *data, + bool shutdown, + bool ignore_errors); /** - * The transfer will use socket 2 to send/recv. `recv_size` is - * the amount to receive or -1 if unknown. With `shutdown` being - * set, the transfer is only allowed to either send OR receive - * and the socket 2 connection will be shutdown at the end of - * the transfer. An unclean shutdown will fail the transfer - * unless `shutdown_err_ignore` is TRUE. + * The transfer will use socket 1 to send/recv. `recv_size` is + * the amount to receive or -1 if unknown. */ -void Curl_xfer_setup2(struct Curl_easy *data, - int send_recv, - curl_off_t recv_size, - bool shutdown, bool shutdown_err_ignore); +void Curl_xfer_setup_sendrecv(struct Curl_easy *data, + int sockindex, + curl_off_t recv_size); /** * Multi has set transfer to DONE. Last chance to trigger @@ -1397,8 +1397,8 @@ static struct connectdata *allocate_conn(struct Curl_easy *data) conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */ conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */ - conn->sockfd = CURL_SOCKET_BAD; - conn->writesockfd = CURL_SOCKET_BAD; + conn->recv_idx = 0; /* default for receiving transfer data */ + conn->send_idx = 0; /* default for sending transfer data */ conn->connection_id = -1; /* no ID */ conn->remote_port = -1; /* unknown at this point */ diff --git a/lib/urldata.h b/lib/urldata.h index ea31d9f5c..a35512cf7 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -672,11 +672,18 @@ struct connectdata { char *oauth_bearer; /* OAUTH2 bearer, allocated */ struct curltime created; /* creation time */ struct curltime lastused; /* when returned to the connection poolas idle */ - curl_socket_t sock[2]; /* two sockets, the second is used for the data - transfer when doing FTP */ + + /* A connection can have one or two sockets and connection filters. + * The protocol using the 2nd one is FTP for CONTROL+DATA sockets */ + curl_socket_t sock[2]; + struct Curl_cfilter *cfilter[2]; /* connection filters */ Curl_recv *recv[2]; Curl_send *send[2]; - struct Curl_cfilter *cfilter[2]; /* connection filters */ + int recv_idx; /* on which socket index to receive, default 0 */ + int send_idx; /* on which socket index to send, default 0 */ + +#define CONN_SOCK_IDX_VALID(i) (((i) >= 0) && ((i) < 2)) + struct { struct curltime start[2]; /* when filter shutdown started */ timediff_t timeout_ms; /* 0 means no timeout */ @@ -698,10 +705,6 @@ struct connectdata { /**** curl_get() phase fields */ - curl_socket_t sockfd; /* socket to read from or CURL_SOCKET_BAD */ - curl_socket_t writesockfd; /* socket to write to, it may be the same we read - from. CURL_SOCKET_BAD disables */ - #ifdef HAVE_GSSAPI BIT(sec_complete); /* if Kerberos is enabled for this connection */ unsigned char command_prot; /* enum protection_level */ @@ -768,7 +771,7 @@ struct connectdata { and happy eyeballing. Use `Curl_conn_get_transport() for actual value once the connection is set up. */ unsigned char ip_version; /* copied from the Curl_easy at creation time */ - /* HTTP version last responded with by the server. + /* HTTP version last responded with by the server or negotiated via ALPN. * 0 at start, then one of 09, 10, 11, etc. */ unsigned char httpversion_seen; unsigned char connect_only; @@ -1348,8 +1351,6 @@ struct UserDefined { void *writeheader; /* write the header to this if non-NULL */ unsigned long httpauth; /* kind of HTTP authentication to use (bitmask) */ unsigned long proxyauth; /* kind of proxy authentication to use (bitmask) */ - long maxredirs; /* maximum no. of http(s) redirects to follow, set to -1 - for infinity */ void *postfields; /* if POST, set the fields' values here */ curl_seek_callback seek_func; /* function that seeks the input */ curl_off_t postfieldsize; /* if POST, this might have a size to use instead @@ -1388,9 +1389,6 @@ struct UserDefined { is to be reused */ timediff_t conn_max_age_ms; /* max time since creation to allow a connection that is to be reused */ -#ifndef CURL_DISABLE_TFTP - long tftp_blksize; /* in bytes, 0 means use default */ -#endif curl_off_t filesize; /* size of file to upload, -1 means unknown */ long low_speed_limit; /* bytes/second */ long low_speed_time; /* number of seconds */ @@ -1422,7 +1420,7 @@ struct UserDefined { unsigned char socks5auth;/* kind of SOCKS5 authentication to use (bitmask) */ #endif struct ssl_general_config general_ssl; /* general user defined SSL stuff */ - int dns_cache_timeout_ms; /* DNS cache timeout (milliseconds) */ + timediff_t dns_cache_timeout_ms; /* DNS cache timeout (milliseconds) */ unsigned int buffer_size; /* size of receive buffer to use */ unsigned int upload_buffer_size; /* size of upload buffer to use, keep it >= CURL_MAX_WRITE_SIZE */ @@ -1485,7 +1483,6 @@ struct UserDefined { int tcp_keepintvl; /* seconds between TCP keepalive probes */ int tcp_keepcnt; /* maximum number of keepalive probes */ - long expect_100_timeout; /* in milliseconds */ #if defined(USE_HTTP2) || defined(USE_HTTP3) struct Curl_data_priority priority; #endif @@ -1505,6 +1502,9 @@ struct UserDefined { #ifdef USE_ECH int tls_ech; /* TLS ECH configuration */ #endif + short maxredirs; /* maximum no. of http(s) redirects to follow, + set to -1 for infinity */ + unsigned short expect_100_timeout; /* in milliseconds */ unsigned short use_port; /* which port to use (when not using default) */ #ifndef CURL_DISABLE_BINDLOCAL unsigned short localport; /* local port number to bind to */ @@ -1512,6 +1512,9 @@ struct UserDefined { in case the 'localport' one cannot be bind()ed */ #endif +#ifndef CURL_DISABLE_TFTP + unsigned short tftp_blksize; /* in bytes, 0 means use default */ +#endif #ifndef CURL_DISABLE_NETRC unsigned char use_netrc; /* enum CURL_NETRC_OPTION values */ #endif diff --git a/lib/vquic/curl_ngtcp2.c b/lib/vquic/curl_ngtcp2.c index 1cb99aaea..646702513 100644 --- a/lib/vquic/curl_ngtcp2.c +++ b/lib/vquic/curl_ngtcp2.c @@ -1955,9 +1955,9 @@ static CURLcode h3_data_pause(struct Curl_cfilter *cf, return CURLE_OK; } -static CURLcode cf_ngtcp2_data_event(struct Curl_cfilter *cf, - struct Curl_easy *data, - int event, int arg1, void *arg2) +static CURLcode cf_ngtcp2_cntrl(struct Curl_cfilter *cf, + struct Curl_easy *data, + int event, int arg1, void *arg2) { struct cf_ngtcp2_ctx *ctx = cf->ctx; CURLcode result = CURLE_OK; @@ -1995,6 +1995,10 @@ static CURLcode cf_ngtcp2_data_event(struct Curl_cfilter *cf, } break; } + case CF_CTRL_CONN_INFO_UPDATE: + if(!cf->sockindex && cf->connected) + cf->conn->httpversion_seen = 30; + break; default: break; } @@ -2733,7 +2737,7 @@ struct Curl_cftype Curl_cft_http3 = { Curl_cf_def_data_pending, cf_ngtcp2_send, cf_ngtcp2_recv, - cf_ngtcp2_data_event, + cf_ngtcp2_cntrl, cf_ngtcp2_conn_is_alive, Curl_cf_def_conn_keep_alive, cf_ngtcp2_query, diff --git a/lib/vquic/curl_osslq.c b/lib/vquic/curl_osslq.c index c18801d81..fa2c0a289 100644 --- a/lib/vquic/curl_osslq.c +++ b/lib/vquic/curl_osslq.c @@ -2168,9 +2168,9 @@ static bool cf_osslq_data_pending(struct Curl_cfilter *cf, return stream && !Curl_bufq_is_empty(&stream->recvbuf); } -static CURLcode cf_osslq_data_event(struct Curl_cfilter *cf, - struct Curl_easy *data, - int event, int arg1, void *arg2) +static CURLcode cf_osslq_cntrl(struct Curl_cfilter *cf, + struct Curl_easy *data, + int event, int arg1, void *arg2) { struct cf_osslq_ctx *ctx = cf->ctx; CURLcode result = CURLE_OK; @@ -2206,6 +2206,10 @@ static CURLcode cf_osslq_data_event(struct Curl_cfilter *cf, } break; } + case CF_CTRL_CONN_INFO_UPDATE: + if(!cf->sockindex && cf->connected) + cf->conn->httpversion_seen = 30; + break; default: break; } @@ -2384,7 +2388,7 @@ struct Curl_cftype Curl_cft_http3 = { cf_osslq_data_pending, cf_osslq_send, cf_osslq_recv, - cf_osslq_data_event, + cf_osslq_cntrl, cf_osslq_conn_is_alive, Curl_cf_def_conn_keep_alive, cf_osslq_query, diff --git a/lib/vquic/curl_quiche.c b/lib/vquic/curl_quiche.c index b981f4d78..179ccf8aa 100644 --- a/lib/vquic/curl_quiche.c +++ b/lib/vquic/curl_quiche.c @@ -40,6 +40,7 @@ #include "../connect.h" #include "../progress.h" #include "../strerror.h" +#include "../select.h" #include "../http1.h" #include "vquic.h" #include "vquic_int.h" @@ -1197,9 +1198,9 @@ static CURLcode h3_data_pause(struct Curl_cfilter *cf, return CURLE_OK; } -static CURLcode cf_quiche_data_event(struct Curl_cfilter *cf, - struct Curl_easy *data, - int event, int arg1, void *arg2) +static CURLcode cf_quiche_cntrl(struct Curl_cfilter *cf, + struct Curl_easy *data, + int event, int arg1, void *arg2) { struct cf_quiche_ctx *ctx = cf->ctx; CURLcode result = CURLE_OK; @@ -1238,6 +1239,10 @@ static CURLcode cf_quiche_data_event(struct Curl_cfilter *cf, } break; } + case CF_CTRL_CONN_INFO_UPDATE: + if(!cf->sockindex && cf->connected) + cf->conn->httpversion_seen = 30; + break; default: break; } @@ -1621,7 +1626,7 @@ struct Curl_cftype Curl_cft_http3 = { cf_quiche_data_pending, cf_quiche_send, cf_quiche_recv, - cf_quiche_data_event, + cf_quiche_cntrl, cf_quiche_conn_is_alive, Curl_cf_def_conn_keep_alive, cf_quiche_query, diff --git a/lib/vquic/vquic.c b/lib/vquic/vquic.c index bebe1df6f..f8ce34129 100644 --- a/lib/vquic/vquic.c +++ b/lib/vquic/vquic.c @@ -642,7 +642,7 @@ CURLcode Curl_qlogdir(struct Curl_easy *data, size_t scidlen, int *qlogfdp) { - const char *qlog_dir = getenv("QLOGDIR"); + char *qlog_dir = curl_getenv("QLOGDIR"); *qlogfdp = -1; if(qlog_dir) { struct dynbuf fname; @@ -667,6 +667,7 @@ CURLcode Curl_qlogdir(struct Curl_easy *data, *qlogfdp = qlogfd; } curlx_dyn_free(&fname); + free(qlog_dir); if(result) return result; } diff --git a/lib/vssh/libssh.c b/lib/vssh/libssh.c index d6ce1a65f..8c366aafa 100644 --- a/lib/vssh/libssh.c +++ b/lib/vssh/libssh.c @@ -1115,8 +1115,8 @@ static int myssh_in_AUTH_DONE(struct Curl_easy *data, /* At this point we have an authenticated ssh session. */ infof(data, "Authentication complete"); Curl_pgrsTime(data, TIMER_APPCONNECT); /* SSH is connected */ - data->conn->sockfd = data->conn->sock[FIRSTSOCKET]; - data->conn->writesockfd = CURL_SOCKET_BAD; + data->conn->recv_idx = FIRSTSOCKET; + data->conn->send_idx = -1; if(data->conn->handler->protocol == CURLPROTO_SFTP) { myssh_to(data, sshc, SSH_SFTP_INIT); @@ -1251,10 +1251,10 @@ static int myssh_in_UPLOAD_INIT(struct Curl_easy *data, Curl_pgrsSetUploadSize(data, data->state.infilesize); } /* upload data */ - Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE); + Curl_xfer_setup_send(data, FIRSTSOCKET); /* not set by Curl_xfer_setup to preserve keepon bits */ - data->conn->sockfd = data->conn->writesockfd; + data->conn->recv_idx = FIRSTSOCKET; /* store this original bitmask setup to use later on if we cannot figure out a "real" bitmask */ @@ -1423,10 +1423,10 @@ static int myssh_in_SFTP_DOWNLOAD_STAT(struct Curl_easy *data, myssh_to(data, sshc, SSH_STOP); return rc; } - Curl_xfer_setup1(data, CURL_XFER_RECV, data->req.size, FALSE); + Curl_xfer_setup_recv(data, FIRSTSOCKET, data->req.size); /* not set by Curl_xfer_setup to preserve keepon bits */ - data->conn->writesockfd = data->conn->sockfd; + data->conn->send_idx = 0; sshc->sftp_recv_state = 0; myssh_to(data, sshc, SSH_STOP); @@ -2240,10 +2240,10 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, } /* upload data */ - Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE); + Curl_xfer_setup_send(data, FIRSTSOCKET); /* not set by Curl_xfer_setup to preserve keepon bits */ - conn->sockfd = conn->writesockfd; + data->conn->recv_idx = FIRSTSOCKET; /* store this original bitmask setup to use later on if we cannot figure out a "real" bitmask */ @@ -2279,10 +2279,10 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, /* download data */ bytecount = ssh_scp_request_get_size(sshc->scp_session); data->req.maxdownload = (curl_off_t) bytecount; - Curl_xfer_setup1(data, CURL_XFER_RECV, bytecount, FALSE); + Curl_xfer_setup_recv(data, FIRSTSOCKET, bytecount); /* not set by Curl_xfer_setup to preserve keepon bits */ - conn->writesockfd = conn->sockfd; + conn->send_idx = 0; myssh_to(data, sshc, SSH_STOP); break; diff --git a/lib/vssh/libssh2.c b/lib/vssh/libssh2.c index bac362dd5..f6985ed25 100644 --- a/lib/vssh/libssh2.c +++ b/lib/vssh/libssh2.c @@ -1199,10 +1199,10 @@ sftp_upload_init(struct Curl_easy *data, Curl_pgrsSetUploadSize(data, data->state.infilesize); } /* upload data */ - Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE); + Curl_xfer_setup_send(data, FIRSTSOCKET); /* not set by Curl_xfer_setup to preserve keepon bits */ - data->conn->sockfd = data->conn->writesockfd; + data->conn->recv_idx = FIRSTSOCKET; /* store this original bitmask setup to use later on if we cannot figure out a "real" bitmask */ @@ -1540,10 +1540,10 @@ sftp_download_stat(struct Curl_easy *data, myssh_state(data, sshc, SSH_STOP); return CURLE_OK; } - Curl_xfer_setup1(data, CURL_XFER_RECV, data->req.size, FALSE); + Curl_xfer_setup_recv(data, FIRSTSOCKET, data->req.size); /* not set by Curl_xfer_setup to preserve keepon bits */ - data->conn->writesockfd = data->conn->sockfd; + data->conn->send_idx = 0; myssh_state(data, sshc, SSH_STOP); @@ -1945,8 +1945,8 @@ static CURLcode ssh_state_auth_done(struct Curl_easy *data, Curl_pgrsTime(data, TIMER_APPCONNECT); /* SSH is connected */ - conn->sockfd = conn->sock[FIRSTSOCKET]; - conn->writesockfd = CURL_SOCKET_BAD; + data->conn->recv_idx = FIRSTSOCKET; + conn->send_idx = -1; if(conn->handler->protocol == CURLPROTO_SFTP) { myssh_state(data, sshc, SSH_SFTP_INIT); @@ -2460,10 +2460,10 @@ static CURLcode ssh_state_scp_download_init(struct Curl_easy *data, /* download data */ bytecount = (curl_off_t)sb.st_size; data->req.maxdownload = (curl_off_t)sb.st_size; - Curl_xfer_setup1(data, CURL_XFER_RECV, bytecount, FALSE); + Curl_xfer_setup_recv(data, FIRSTSOCKET, bytecount); /* not set by Curl_xfer_setup to preserve keepon bits */ - data->conn->writesockfd = data->conn->sockfd; + data->conn->send_idx = 0; myssh_state(data, sshc, SSH_STOP); return CURLE_OK; @@ -2609,10 +2609,10 @@ static CURLcode ssh_state_scp_upload_init(struct Curl_easy *data, /* upload data */ data->req.size = data->state.infilesize; Curl_pgrsSetUploadSize(data, data->state.infilesize); - Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE); + Curl_xfer_setup_send(data, FIRSTSOCKET); /* not set by Curl_xfer_setup to preserve keepon bits */ - data->conn->sockfd = data->conn->writesockfd; + data->conn->recv_idx = FIRSTSOCKET; /* store this original bitmask setup to use later on if we cannot figure out a "real" bitmask */ diff --git a/lib/vssh/wolfssh.c b/lib/vssh/wolfssh.c index 15f504a01..556eda0cb 100644 --- a/lib/vssh/wolfssh.c +++ b/lib/vssh/wolfssh.c @@ -717,10 +717,10 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, Curl_pgrsSetUploadSize(data, data->state.infilesize); } /* upload data */ - Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE); + Curl_xfer_setup_send(data, FIRSTSOCKET); /* not set by Curl_xfer_setup to preserve keepon bits */ - conn->sockfd = conn->writesockfd; + data->conn->recv_idx = FIRSTSOCKET; if(result) { wssh_state(data, sshc, SSH_SFTP_CLOSE); @@ -816,10 +816,10 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, wssh_state(data, sshc, SSH_STOP); break; } - Curl_xfer_setup1(data, CURL_XFER_RECV, data->req.size, FALSE); + Curl_xfer_setup_recv(data, FIRSTSOCKET, data->req.size); /* not set by Curl_xfer_setup to preserve keepon bits */ - conn->writesockfd = conn->sockfd; + conn->send_idx = 0; if(result) { /* this should never occur; the close state should be entered diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index 3cc0d8630..dc4a6d122 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -1856,8 +1856,10 @@ static CURLcode x509_name_oneline(X509_NAME *a, struct dynbuf *d) CURLcode result = CURLE_OUT_OF_MEMORY; if(bio_out) { + unsigned long flags = XN_FLAG_SEP_SPLUS_SPC | + (XN_FLAG_ONELINE & ~ASN1_STRFLGS_ESC_MSB & ~XN_FLAG_SPC_EQ); curlx_dyn_reset(d); - rc = X509_NAME_print_ex(bio_out, a, 0, XN_FLAG_SEP_SPLUS_SPC); + rc = X509_NAME_print_ex(bio_out, a, 0, flags); if(rc != -1) { BIO_get_mem_ptr(bio_out, &biomem); result = curlx_dyn_addn(d, biomem->data, biomem->length); @@ -3325,8 +3327,10 @@ static CURLcode import_windows_cert_store(struct Curl_easy *data, continue; x509 = d2i_X509(NULL, &encoded_cert, (long)pContext->cbCertEncoded); - if(!x509) + if(!x509) { + ERR_clear_error(); continue; + } /* Try to import the certificate. This may fail for legitimate reasons such as duplicate certificate, which is allowed by MS but diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c index 27aceaba8..0b3ec8cc2 100644 --- a/lib/vtls/schannel.c +++ b/lib/vtls/schannel.c @@ -730,6 +730,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf, if(!client_certs[0]) { /* CRYPT_E_NOT_FOUND / E_INVALIDARG */ CertCloseStore(cert_store, 0); + failf(data, "schannel: client cert not found in cert store"); return CURLE_SSL_CERTPROBLEM; } } diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c index 96d64dd60..f17f9142b 100644 --- a/lib/vtls/vtls.c +++ b/lib/vtls/vtls.c @@ -1605,6 +1605,30 @@ static CURLcode ssl_cf_query(struct Curl_cfilter *cf, CURLE_UNKNOWN_OPTION; } +static CURLcode ssl_cf_cntrl(struct Curl_cfilter *cf, + struct Curl_easy *data, + int event, int arg1, void *arg2) +{ + struct ssl_connect_data *connssl = cf->ctx; + + (void)arg1; + (void)arg2; + (void)data; + switch(event) { + case CF_CTRL_CONN_INFO_UPDATE: + if(connssl->negotiated.alpn && !cf->sockindex) { + if(!strcmp("http/1.1", connssl->negotiated.alpn)) + cf->conn->httpversion_seen = 11; + else if(!strcmp("h2", connssl->negotiated.alpn)) + cf->conn->httpversion_seen = 20; + else if(!strcmp("h3", connssl->negotiated.alpn)) + cf->conn->httpversion_seen = 30; + } + break; + } + return CURLE_OK; +} + static bool cf_ssl_is_alive(struct Curl_cfilter *cf, struct Curl_easy *data, bool *input_pending) { @@ -1628,7 +1652,7 @@ struct Curl_cftype Curl_cft_ssl = { ssl_cf_data_pending, ssl_cf_send, ssl_cf_recv, - Curl_cf_def_cntrl, + ssl_cf_cntrl, cf_ssl_is_alive, Curl_cf_def_conn_keep_alive, ssl_cf_query, diff --git a/lib/vtls/wolfssl.c b/lib/vtls/wolfssl.c index e98cf8714..9a84b3384 100644 --- a/lib/vtls/wolfssl.c +++ b/lib/vtls/wolfssl.c @@ -243,12 +243,12 @@ static const struct group_name_map gnm[] = { { WOLFSSL_ML_KEM_512, "ML_KEM_512" }, { WOLFSSL_ML_KEM_768, "ML_KEM_768" }, { WOLFSSL_ML_KEM_1024, "ML_KEM_1024" }, - { WOLFSSL_P256_ML_KEM_512, "P256_ML_KEM_512" }, - { WOLFSSL_P384_ML_KEM_768, "P384_ML_KEM_768" }, - { WOLFSSL_P521_ML_KEM_1024, "P521_ML_KEM_1024" }, - { WOLFSSL_P256_ML_KEM_768, "P256_ML_KEM_768" }, - { WOLFSSL_P384_ML_KEM_1024, "P384_ML_KEM_1024" }, - { WOLFSSL_X25519_ML_KEM_768, "X25519_ML_KEM_768" }, + { WOLFSSL_SECP256R1MLKEM512, "SecP256r1MLKEM512" }, + { WOLFSSL_SECP384R1MLKEM768, "SecP384r1MLKEM768" }, + { WOLFSSL_SECP521R1MLKEM1024, "SecP521r1MLKEM1024" }, + { WOLFSSL_SECP256R1MLKEM768, "SecP256r1MLKEM768" }, + { WOLFSSL_SECP384R1MLKEM1024, "SecP384r1MLKEM1024" }, + { WOLFSSL_X25519MLKEM768, "X25519MLKEM768" }, { 0, NULL } }; #endif |