Make `port` member in these struct of type `uint16_t`.
add `uint8_t transport` to `struct ip_quadruple
Define TRNSPRT_NONE as 0. By assigning a valid transport only on a
successful connection, it is clear when the ip_quadruple members are
valid. Also, for transports not involving ports, the getinfos for
`CURLINFO_PRIMARY_PORT` and `CURLINFO_LOCAL_PORT` will now always return
-1.
Make all `transport` members and parameters of type `uint8_t`.
Document the return value of `CURLINFO_LOCAL_PORT` and
`CURLINFO_PRIMARY_PORT` in this regard. Add tests that writeout stats
report ports correctly.
Closes #19708
If the connection was done using QUIC, the port number is a UDP port number,
otherwise it is a TCP port number.
+If no connection was established or if the protocol does not use ports, -1
+is returned.
+
# %PROTOCOLS%
# EXAMPLE
the proxy, if no proxy was used it is the port number of the most recently
accessed URL.
+If the connection was done using QUIC, the port number is a UDP port number.
+
+If no connection was established or if the protocol does not use ports, -1
+is returned.
+
# %PROTOCOLS%
# EXAMPLE
CURLcode result;
struct curltime started;
int reply_ms;
- unsigned char transport;
+ uint8_t transport;
enum alpnid alpn_id;
BIT(shutdown);
};
static void cf_hc_baller_assign(struct cf_hc_baller *b,
enum alpnid alpn_id,
- unsigned char def_transport)
+ uint8_t def_transport)
{
b->alpn_id = alpn_id;
b->transport = def_transport;
static void cf_hc_baller_init(struct cf_hc_baller *b,
struct Curl_cfilter *cf,
struct Curl_easy *data,
- int transport)
+ uint8_t transport)
{
struct Curl_cfilter *save = cf->next;
static CURLcode cf_hc_create(struct Curl_cfilter **pcf,
struct Curl_easy *data,
enum alpnid *alpnids, size_t alpn_count,
- unsigned char def_transport)
+ uint8_t def_transport)
{
struct Curl_cfilter *cf = NULL;
struct cf_hc_ctx *ctx;
struct connectdata *conn,
int sockindex,
enum alpnid *alpn_ids, size_t alpn_count,
- unsigned char def_transport)
+ uint8_t def_transport)
{
struct Curl_cfilter *cf;
CURLcode result = CURLE_OK;
struct transport_provider {
- int transport;
+ uint8_t transport;
cf_ip_connect_create *cf_create;
};
#endif
};
-static cf_ip_connect_create *get_cf_create(int transport)
+static cf_ip_connect_create *get_cf_create(uint8_t transport)
{
size_t i;
for(i = 0; i < CURL_ARRAYSIZE(transport_providers); ++i) {
#ifdef UNITTESTS
/* used by unit2600.c */
-void Curl_debug_set_transport_provider(int transport,
+void Curl_debug_set_transport_provider(uint8_t transport,
cf_ip_connect_create *cf_create)
{
size_t i;
struct curltime started; /* start of current attempt */
CURLcode result;
int ai_family;
- int transport;
+ uint8_t transport;
int error;
BIT(connected); /* cf has connected */
BIT(shutdown); /* cf has shutdown */
struct Curl_easy *data,
const struct Curl_addrinfo *addr,
int ai_family,
- int transport,
+ uint8_t transport,
cf_ip_connect_create *cf_create)
{
struct Curl_cfilter *wcf;
struct curltime last_attempt_started;
timediff_t attempt_delay_ms;
int last_attempt_ai_family;
- int transport;
+ uint8_t transport;
};
static CURLcode cf_ip_attempt_restart(struct cf_ip_attempt *a,
static CURLcode cf_ip_ballers_init(struct cf_ip_ballers *bs, int ip_version,
const struct Curl_addrinfo *addr_list,
cf_ip_connect_create *cf_create,
- int transport,
+ uint8_t transport,
timediff_t attempt_delay_ms)
{
memset(bs, 0, sizeof(*bs));
} cf_connect_state;
struct cf_ip_happy_ctx {
- int transport;
+ uint8_t transport;
cf_ip_connect_create *cf_create;
cf_connect_state state;
struct cf_ip_ballers ballers;
return CURLE_OPERATION_TIMEDOUT;
}
- CURL_TRC_CF(data, cf, "init ip ballers for transport %d", ctx->transport);
+ CURL_TRC_CF(data, cf, "init ip ballers for transport %u", ctx->transport);
ctx->started = curlx_now();
return cf_ip_ballers_init(&ctx->ballers, cf->conn->ip_version,
dns->addr, ctx->cf_create, ctx->transport,
struct Curl_easy *data,
struct connectdata *conn,
cf_ip_connect_create *cf_create,
- int transport)
+ uint8_t transport)
{
struct cf_ip_happy_ctx *ctx = NULL;
CURLcode result;
CURLcode cf_ip_happy_insert_after(struct Curl_cfilter *cf_at,
struct Curl_easy *data,
- int transport)
+ uint8_t transport)
{
cf_ip_connect_create *cf_create;
struct Curl_cfilter *cf;
DEBUGASSERT(cf_at);
cf_create = get_cf_create(transport);
if(!cf_create) {
- CURL_TRC_CF(data, cf_at, "unsupported transport type %d", transport);
+ CURL_TRC_CF(data, cf_at, "unsupported transport type %u", transport);
return CURLE_UNSUPPORTED_PROTOCOL;
}
result = cf_ip_happy_create(&cf, data, cf_at->conn, cf_create, transport);
struct Curl_easy *data,
struct connectdata *conn,
const struct Curl_addrinfo *ai,
- int transport);
+ uint8_t transport);
CURLcode cf_ip_happy_insert_after(struct Curl_cfilter *cf_at,
struct Curl_easy *data,
- int transport);
+ uint8_t transport);
extern struct Curl_cftype Curl_cft_ip_happy;
#ifdef UNITTESTS
-void Curl_debug_set_transport_provider(int transport,
+void Curl_debug_set_transport_provider(uint8_t transport,
cf_ip_connect_create *cf_create);
#endif
*/
static CURLcode sock_assign_addr(struct Curl_sockaddr_ex *dest,
const struct Curl_addrinfo *ai,
- int transport)
+ uint8_t transport)
{
/*
* The Curl_sockaddr_ex structure is basically libcurl's external API
CURLcode Curl_socket_open(struct Curl_easy *data,
const struct Curl_addrinfo *ai,
struct Curl_sockaddr_ex *addr,
- int transport,
+ uint8_t transport,
curl_socket_t *sockfd)
{
struct Curl_sockaddr_ex dummy;
}
struct cf_socket_ctx {
- int transport;
+ uint8_t transport;
struct Curl_sockaddr_ex addr; /* address to connect to */
curl_socket_t sock; /* current attempt socket */
struct ip_quadruple ip; /* The IP quadruple 2x(addr+port) */
static CURLcode cf_socket_ctx_init(struct cf_socket_ctx *ctx,
const struct Curl_addrinfo *ai,
- int transport)
+ uint8_t transport)
{
CURLcode result;
{
struct cf_socket_ctx *ctx = cf->ctx;
ctx->ip.local_ip[0] = 0;
- ctx->ip.local_port = -1;
+ ctx->ip.local_port = 0;
#ifdef HAVE_GETSOCKNAME
if((ctx->sock != CURL_SOCKET_BAD) &&
struct cf_socket_ctx *ctx = cf->ctx;
/* store remote address and port used in this connection attempt */
+ ctx->ip.transport = ctx->transport;
if(!Curl_addr2string(&ctx->addr.curl_sa_addr,
(curl_socklen_t)ctx->addr.addrlen,
ctx->ip.remote_ip, &ctx->ip.remote_port)) {
struct Curl_easy *data,
struct connectdata *conn,
const struct Curl_addrinfo *ai,
- int transport)
+ uint8_t transport)
{
struct cf_socket_ctx *ctx = NULL;
struct Curl_cfilter *cf = NULL;
struct Curl_easy *data,
struct connectdata *conn,
const struct Curl_addrinfo *ai,
- int transport)
+ uint8_t transport)
{
struct cf_socket_ctx *ctx = NULL;
struct Curl_cfilter *cf = NULL;
struct Curl_easy *data,
struct connectdata *conn,
const struct Curl_addrinfo *ai,
- int transport)
+ uint8_t transport)
{
struct cf_socket_ctx *ctx = NULL;
struct Curl_cfilter *cf = NULL;
CURLcode Curl_socket_open(struct Curl_easy *data,
const struct Curl_addrinfo *ai,
struct Curl_sockaddr_ex *addr,
- int transport,
+ uint8_t transport,
curl_socket_t *sockfd);
int Curl_socket_close(struct Curl_easy *data, struct connectdata *conn,
struct Curl_easy *data,
struct connectdata *conn,
const struct Curl_addrinfo *ai,
- int transport);
+ uint8_t transport);
/**
* Creates a cfilter that opens a UDP socket to the given address
struct Curl_easy *data,
struct connectdata *conn,
const struct Curl_addrinfo *ai,
- int transport);
+ uint8_t transport);
/**
* Creates a cfilter that opens a UNIX socket to the given address
struct Curl_easy *data,
struct connectdata *conn,
const struct Curl_addrinfo *ai,
- int transport);
+ uint8_t transport);
/**
* Creates a cfilter that keeps a listening socket.
/* retrieves ip address and port from a sockaddr structure. note it calls
curlx_inet_ntop which sets errno on fail, not SOCKERRNO. */
bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
- char *addr, int *port)
+ char *addr, uint16_t *port)
{
struct sockaddr_in *si = NULL;
#ifdef USE_IPV6
case AF_INET:
si = (struct sockaddr_in *)(void *) sa;
if(curlx_inet_ntop(sa->sa_family, &si->sin_addr, addr, MAX_IPADR_LEN)) {
- unsigned short us_port = ntohs(si->sin_port);
- *port = us_port;
+ *port = ntohs(si->sin_port);
return TRUE;
}
break;
si6 = (struct sockaddr_in6 *)(void *) sa;
if(curlx_inet_ntop(sa->sa_family, &si6->sin6_addr, addr,
MAX_IPADR_LEN)) {
- unsigned short us_port = ntohs(si6->sin6_port);
- *port = us_port;
+ *port = ntohs(si6->sin6_port);
return TRUE;
}
break;
struct cf_setup_ctx {
cf_setup_state state;
int ssl_mode;
- int transport;
+ uint8_t transport;
};
static CURLcode cf_setup_connect(struct Curl_cfilter *cf,
static CURLcode cf_setup_create(struct Curl_cfilter **pcf,
struct Curl_easy *data,
- int transport,
+ uint8_t transport,
int ssl_mode)
{
struct Curl_cfilter *cf = NULL;
static CURLcode cf_setup_add(struct Curl_easy *data,
struct connectdata *conn,
int sockindex,
- int transport,
+ uint8_t transport,
int ssl_mode)
{
struct Curl_cfilter *cf;
CURLcode Curl_cf_setup_insert_after(struct Curl_cfilter *cf_at,
struct Curl_easy *data,
- int transport,
+ uint8_t transport,
int ssl_mode)
{
struct Curl_cfilter *cf;
struct connectdata **connp);
bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
- char *addr, int *port);
+ char *addr, uint16_t *port);
/*
* Curl_conncontrol() marks the end of a connection/stream. The 'closeit'
CURLcode Curl_cf_setup_insert_after(struct Curl_cfilter *cf_at,
struct Curl_easy *data,
- int transport,
+ uint8_t transport,
int ssl_mode);
/**
info->wouldredirect = NULL;
memset(&info->primary, 0, sizeof(info->primary));
- info->primary.remote_port = -1;
- info->primary.local_port = -1;
info->retry_after = 0;
info->conn_scheme = 0;
break;
case CURLINFO_PRIMARY_PORT:
/* Return the (remote) port of the most recent (primary) connection */
- *param_longp = data->info.primary.remote_port;
+ if(CUR_IP_QUAD_HAS_PORTS(&data->info.primary))
+ *param_longp = data->info.primary.remote_port;
+ else
+ *param_longp = -1;
break;
case CURLINFO_LOCAL_PORT:
/* Return the local port of the most recent (primary) connection */
- *param_longp = data->info.primary.local_port;
+ if(CUR_IP_QUAD_HAS_PORTS(&data->info.primary))
+ *param_longp = data->info.primary.local_port;
+ else
+ *param_longp = -1;
break;
case CURLINFO_PROXY_ERROR:
*param_longp = (long)data->info.pxcode;
#endif
#ifndef CURL_DISABLE_PROXY
case CURLOPT_PROXYPORT:
- if((arg < 0) || (arg > 65535))
+ if((arg < 0) || (arg > UINT16_MAX))
return CURLE_BAD_FUNCTION_ARGUMENT;
- s->proxyport = (unsigned short)arg;
+ s->proxyport = (uint16_t)arg;
break;
case CURLOPT_PROXYAUTH:
long proxytype)
{
char *portptr = NULL;
- int port = -1;
char *proxyuser = NULL;
char *proxypasswd = NULL;
char *host = NULL;
if(portptr) {
curl_off_t num;
const char *p = portptr;
- if(!curlx_str_number(&p, &num, 0xffff))
- port = (int)num;
+ if(!curlx_str_number(&p, &num, UINT16_MAX))
+ proxyinfo->port = (uint16_t)num;
+ /* Should we not error out when the port number is invalid? */
free(portptr);
}
else {
if(data->set.proxyport)
/* None given in the proxy string, then get the default one if it is
given */
- port = (int)data->set.proxyport;
+ proxyinfo->port = data->set.proxyport;
else {
if(IS_HTTPS_PROXY(proxytype))
- port = CURL_DEFAULT_HTTPS_PROXY_PORT;
+ proxyinfo->port = CURL_DEFAULT_HTTPS_PROXY_PORT;
else
- port = CURL_DEFAULT_PROXY_PORT;
+ proxyinfo->port = CURL_DEFAULT_PROXY_PORT;
}
}
- if(port >= 0)
- proxyinfo->port = port;
/* now, clone the proxy hostname */
uc = curl_url_get(uhp, CURLUPART_HOST, &host, CURLU_URLDECODE);
CURLcode (*follow)(struct Curl_easy *data, const char *newurl,
followtype type);
- int defport; /* Default port. */
+ uint16_t defport; /* Default port. */
curl_prot_t protocol; /* See CURLPROTO_* - this needs to be the single
specific protocol bit */
curl_prot_t family; /* single bit for protocol family; basically the
#define CONNRESULT_NONE 0 /* No extra information. */
#define CONNRESULT_DEAD (1<<0) /* The connection is dead. */
+#define TRNSPRT_NONE 0
+#define TRNSPRT_TCP 3
+#define TRNSPRT_UDP 4
+#define TRNSPRT_QUIC 5
+#define TRNSPRT_UNIX 6
+
struct ip_quadruple {
char remote_ip[MAX_IPADR_LEN];
char local_ip[MAX_IPADR_LEN];
- int remote_port;
- int local_port;
+ uint16_t remote_port;
+ uint16_t local_port;
+ uint8_t transport;
};
+#define CUR_IP_QUAD_HAS_PORTS(x) (((x)->transport == TRNSPRT_TCP) || \
+ ((x)->transport == TRNSPRT_UDP) || \
+ ((x)->transport == TRNSPRT_QUIC))
+
struct proxy_info {
struct hostname host;
- int port;
+ uint16_t port;
unsigned char proxytype; /* what kind of proxy that is in use */
char *user; /* proxy username string, allocated */
char *passwd; /* proxy password string, allocated */
};
-#define TRNSPRT_TCP 3
-#define TRNSPRT_UDP 4
-#define TRNSPRT_QUIC 5
-#define TRNSPRT_UNIX 6
-
/*
* The connectdata struct contains all fields and variables that should be
* unique for an entire connection.
#ifndef CURL_DISABLE_PROXY
struct ssl_config_data proxy_ssl; /* user defined SSL stuff for proxy */
struct curl_slist *proxyheaders; /* linked list of extra CONNECT headers */
- unsigned short proxyport; /* If non-zero, use this port number by
+ uint16_t proxyport; /* If non-zero, use this port number by
default. If the proxy string features a
":[port]" that one will override this. */
unsigned char proxytype; /* what kind of proxy */
struct Curl_easy *data,
struct connectdata *conn,
const struct Curl_addrinfo *ai,
- int transport)
+ uint8_t transport)
{
(void)transport;
DEBUGASSERT(transport == TRNSPRT_QUIC);
struct Curl_easy *data,
struct connectdata *conn,
const struct Curl_addrinfo *ai,
- int transport);
+ uint8_t transport);
extern struct Curl_cftype Curl_cft_http3;
# there are cases where time_connect is reported as 0
assert r.stats[0]['time_connect'] >= 0, f'{r.stats[0]}'
assert r.stats[0]['time_appconnect'] > 0, f'{r.stats[0]}'
+ # ports are reported correctly
+ assert r.stats[0]['remote_port'] == env.port_for(proto), f'{r.dump_logs()}'
+ assert r.stats[0]['local_port'] > 0, f'{r.dump_logs()}'
# simple https: HEAD
@pytest.mark.parametrize("proto", Env.http_protos())
'--unix-socket', uds_faker.path,
])
r.check_response(count=1, http_status=200)
+ assert r.stats[0]['remote_port'] == -1, f'{r.dump_logs()}'
+ assert r.stats[0]['local_port'] == -1, f'{r.dump_logs()}'
# download https: via Unix socket
@pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason="curl without SSL")
'--unix-socket', uds_faker.path,
])
r.check_response(exitcode=35, http_status=None)
+ assert r.stats[0]['remote_port'] == -1, f'{r.dump_logs()}'
+ assert r.stats[0]['local_port'] == -1, f'{r.dump_logs()}'
# download HTTP/3 via Unix socket
@pytest.mark.skipif(condition=not Env.have_h3(), reason='h3 not supported')
'--unix-socket', uds_faker.path,
])
r.check_response(exitcode=96, http_status=None)
+ assert r.stats[0]['remote_port'] == -1, f'{r.dump_logs()}'
+ assert r.stats[0]['local_port'] == -1, f'{r.dump_logs()}'
addr = dns ? dns->addr : NULL;
for(j = 0; j < addressnum; ++j) {
- int port = 0;
+ uint16_t port = 0;
char ipaddress[MAX_IPADR_LEN] = {0};
if(!addr && !tests[i].address[j])
addr = dns ? dns->addr : NULL;
for(j = 0; j < addressnum; ++j) {
- int port = 0;
+ uint16_t port = 0;
char ipaddress[MAX_IPADR_LEN] = {0};
if(!addr && !tests[i].address[j])
struct cf_test_ctx {
int idx;
int ai_family;
- int transport;
+ uint8_t transport;
char id[16];
struct curltime started;
timediff_t fail_delay_ms;
struct Curl_easy *data,
struct connectdata *conn,
const struct Curl_addrinfo *ai,
- int transport)
+ uint8_t transport)
{
static const struct Curl_cftype cft_test = {
"TEST",