ecl
ECONNREFUSED
eCOS
+ECT
+EF
EFnet
EGD
EHLO
logfile
lookups
loopback
+LOWCOST
+LOWDELAY
LPRT
LSB
lseek
MicroBlaze
MicroOS
middlebox
+MINCOST
mingw
MinGW
MINIX
toolchains
toolset
toplevel
+TOS
TPF
TrackMemory
transcode
include.md \
insecure.md \
interface.md \
+ ip-tos.md \
ipfs-gateway.md \
ipv4.md \
ipv6.md \
--- /dev/null
+---
+c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+SPDX-License-Identifier: curl
+Long: ip-tos
+Arg: <string>
+Help: Set IP Type of Service or Traffic Class
+Added: 8.9.0
+Category: connection
+Protocols: All
+Multi: single
+See-also:
+ - tcp-nodelay
+Example:
+ - --ip-tos CS5 $URL
+---
+
+# `--ip-tos`
+
+Set Type of Service (TOS) for IPv4 or Traffic Class for IPv6. (Added in 8.9.0).
+
+The values allowed for \<string\> can be a numeric value between 1 and 255
+or one of the following:
+
+* CS0
+* CS1
+* CS2
+* CS3
+* CS4
+* CS5
+* CS6
+* CS7
+* AF11
+* AF12
+* AF13
+* AF21
+* AF22
+* AF23
+* AF31
+* AF32
+* AF33
+* AF41
+* AF42
+* AF43
+* EF
+* VOICE-ADMIT
+* ECT1
+* ECT0
+* CE
+* LE
+* LOWCOST
+* LOWDELAY
+* THROUGHPUT
+* RELIABILITY
+* MINCOST
--http3 7.66.0
--http3-only 7.88.0
--ignore-content-length 7.14.1
+--ip-tos 8.9.0
--ipfs-gateway 8.4.0
--include (-i) 4.8
--insecure (-k) 7.10
char *range;
long low_speed_limit;
long low_speed_time;
+ long ip_tos; /* IP Type of Service */
char *dns_servers; /* dot notation: 1.1.1.1;2.2.2.2 */
char *dns_interface; /* interface name */
char *dns_ipv4_addr; /* dot notation */
C_TRACE_CONFIG,
C_TRACE_IDS,
C_TRACE_TIME,
+ C_IP_TOS,
C_UNIX_SOCKET,
C_UPLOAD_FILE,
C_URL,
{"include", ARG_BOOL, 'i', C_INCLUDE},
{"insecure", ARG_BOOL, 'k', C_INSECURE},
{"interface", ARG_STRG, ' ', C_INTERFACE},
+ {"ip-tos", ARG_STRG, ' ', C_IP_TOS},
{"ipfs-gateway", ARG_STRG, ' ', C_IPFS_GATEWAY},
{"ipv4", ARG_NONE, '4', C_IPV4},
{"ipv6", ARG_NONE, '6', C_IPV6},
return singles[letter - ' '];
}
+struct TOSEntry {
+ const char *name;
+ unsigned char value;
+};
+
+static const struct TOSEntry tos_entries[] = {
+ {"AF11", 0x28},
+ {"AF12", 0x30},
+ {"AF13", 0x38},
+ {"AF21", 0x48},
+ {"AF22", 0x50},
+ {"AF23", 0x58},
+ {"AF31", 0x68},
+ {"AF32", 0x70},
+ {"AF33", 0x78},
+ {"AF41", 0x88},
+ {"AF42", 0x90},
+ {"AF43", 0x98},
+ {"CE", 0x03},
+ {"CS0", 0x00},
+ {"CS1", 0x20},
+ {"CS2", 0x40},
+ {"CS3", 0x60},
+ {"CS4", 0x80},
+ {"CS5", 0xa0},
+ {"CS6", 0xc0},
+ {"CS7", 0xe0},
+ {"ECT0", 0x02},
+ {"ECT1", 0x01},
+ {"EF", 0xb8},
+ {"LE", 0x04},
+ {"LOWCOST", 0x02},
+ {"LOWDELAY", 0x10},
+ {"MINCOST", 0x02},
+ {"RELIABILITY", 0x04},
+ {"THROUGHPUT", 0x08},
+ {"VOICE-ADMIT", 0xb0}
+};
+
+static int find_tos(const void *a, const void *b)
+{
+ const struct TOSEntry *aa = a;
+ const struct TOSEntry *bb = b;
+ return strcmp(aa->name, bb->name);
+}
+
#define MAX_QUERY_LEN 100000 /* larger is not likely to ever work */
static ParameterError url_query(char *nextarg,
struct GlobalConfig *global,
case C_TCP_NODELAY: /* --tcp-nodelay */
config->tcp_nodelay = toggle;
break;
+ case C_IP_TOS: { /* --ip-tos */
+ const struct TOSEntry *entry = bsearch(
+ &nextarg, tos_entries, sizeof(tos_entries)/sizeof(*tos_entries),
+ sizeof(*tos_entries), find_tos);
+ if(entry)
+ config->ip_tos = entry->value;
+ else /* numeric tos value */
+ err = str2unummax(&config->ip_tos, nextarg, 0xFF);
+ break;
+ }
case C_PROXY_DIGEST: /* --proxy-digest */
config->proxydigest = toggle;
break;
{" --interface <name>",
"Use network interface",
CURLHELP_CONNECTION},
+ {" --ip-tos <string>",
+ "Set IP Type of Service or Traffic Class",
+ CURLHELP_CONNECTION},
{" --ipfs-gateway <URL>",
"Gateway for IPFS",
CURLHELP_IPFS},
# include <proto/dos.h>
#endif
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+
#define ENABLE_CURLX_PRINTF
/* use our own printf() functions */
#include "curlx.h"
# define O_BINARY 0
#endif
+#ifndef SOL_IP
+# define SOL_IP IPPROTO_IP
+#endif
+
#define CURL_CA_CERT_ERRORMSG \
"More details here: https://curl.se/docs/sslcerts.html\n\n" \
"curl failed to verify the legitimacy of the server and therefore " \
}
}
+#ifdef IP_TOS
+static int get_address_family(curl_socket_t sockfd)
+{
+ struct sockaddr_storage addr;
+ socklen_t addrlen = sizeof(addr);
+ if(getsockname(sockfd, (struct sockaddr *)&addr, &addrlen) == 0)
+ return addr.ss_family;
+ return AF_UNSPEC;
+}
+#endif
+
+#if defined(IP_TOS) || defined(IPV6_TCLASS)
+static int sockopt_callback(void *clientp, curl_socket_t curlfd,
+ curlsocktype purpose)
+{
+ struct OperationConfig *config = (struct OperationConfig *)clientp;
+ if(purpose != CURLSOCKTYPE_IPCXN)
+ return CURL_SOCKOPT_OK;
+ (void)config;
+ (void)curlfd;
+ if(config->ip_tos > 0) {
+ int tos = (int)config->ip_tos;
+ int result = 0;
+ switch(get_address_family(curlfd)) {
+ case AF_INET:
+#ifdef IP_TOS
+ result = setsockopt(curlfd, SOL_IP, IP_TOS,
+ (const char *)&tos, sizeof(tos));
+#endif
+ break;
+ case AF_INET6:
+#ifdef IPV6_TCLASS
+ result = setsockopt(curlfd, IPPROTO_IPV6, IPV6_TCLASS,
+ (const char *)&tos, sizeof(tos));
+#endif
+ break;
+ }
+ if(result < 0) {
+ int error = errno;
+ warnf(config->global,
+ "Setting type of service to %d failed with errno %d: %s;\n",
+ tos, error, strerror(error));
+ }
+ }
+ return CURL_SOCKOPT_OK;
+}
+#endif
+
+
#ifdef __VMS
/*
* get_vms_file_size does what it takes to get the real size of the file
my_setopt_str(curl, CURLOPT_ECH, config->ech_config);
#endif
+ /* new in 8.9.0 */
+ if(config->ip_tos > 0) {
+#if defined(IP_TOS) || defined(IPV6_TCLASS)
+ my_setopt(curl, CURLOPT_SOCKOPTFUNCTION, sockopt_callback);
+ my_setopt(curl, CURLOPT_SOCKOPTDATA, config);
+#else
+ warnf(config->global,
+ "Type of service is not supported in this build.");
+#endif
+ }
+
/* initialize retry vars for loop below */
per->retry_sleep_default = (config->retry_delay) ?
config->retry_delay*1000L : RETRY_SLEEP_DEFAULT; /* ms */