Add multipath support

This commit is contained in:
Jop Zitman 2024-12-16 18:33:21 +08:00
parent 19ef155749
commit 0006c48e4b
8 changed files with 141 additions and 25 deletions

View file

@ -43,9 +43,11 @@ add_executable(slipstream
src/slipstream_server.c
src/slipstream_server_circular_query_buffer.c
src/slipstream_inline_dots.c
src/slipstream_resolver_addresses.c
include/slipstream.h
include/slipstream_server_circular_query_buffer.h
include/slipstream_inline_dots.h
include/slipstream_resolver_addresses.h
extern/lua-resty-base-encoding/b32_data.h
extern/lua-resty-base-encoding/base32.c

View file

@ -20,7 +20,7 @@ extern "C" {
int picoquic_slipstream_client(int listen_port, char const* server_name, int server_port, const char* domain_name);
int picoquic_slipstream_client(int listen_port, char const* resolver_addresses_filename, const char* domain_name);
int picoquic_slipstream_server(int server_port, const char* pem_cert, const char* pem_key, char const* upstream_name,
int upstream_port, const char* domain_name);

View file

@ -0,0 +1,8 @@
#ifndef SLIPSTREAM_RESOLVERS_H
#define SLIPSTREAM_RESOLVERS_H
#include <stdio.h>
struct sockaddr_storage* read_resolver_addresses(const char *resolver_addresses_filename, size_t *count);
#endif //SLIPSTREAM_RESOLVERS_H

5
resolvers-trusted.txt Normal file
View file

@ -0,0 +1,5 @@
127.0.0.1 8853
127.0.0.2 8853
127.0.0.3 8853
127.0.0.4 8853
172.17.0.1 8853

View file

@ -34,15 +34,14 @@ int main(int argc, char** argv)
usage(argv[0]);
}
else if (strcmp(argv[1], "client") == 0) {
if (argc != 6) {
if (argc != 5) {
usage(argv[0]);
}
else {
int local_port = atoi(argv[2]);
char const* remote_ip = argv[3];
int remote_port = atoi(argv[4]);
const char* domain_name = argv[5];
exit_code = picoquic_slipstream_client(local_port, remote_ip, remote_port, domain_name);
char const* resolver_addresses_filename = argv[3];
const char* domain_name = argv[4];
exit_code = picoquic_slipstream_client(local_port, resolver_addresses_filename, domain_name);
}
}
else if (strcmp(argv[1], "server") == 0) {

View file

@ -19,6 +19,7 @@
#include "picoquic_config.h"
#include "slipstream.h"
#include "slipstream_inline_dots.h"
#include "slipstream_resolver_addresses.h"
#include "SPCDNS/src/dns.h"
#include "SPCDNS/src/mappings.h"
@ -163,6 +164,8 @@ typedef struct st_slipstream_client_ctx_t {
picoquic_cnx_t* cnx;
slipstream_client_stream_ctx_t* first_stream;
picoquic_network_thread_ctx_t* thread_ctx;
struct sockaddr_storage* server_addresses;
size_t server_address_count;
} slipstream_client_ctx_t;
slipstream_client_stream_ctx_t* slipstream_client_create_stream_ctx(picoquic_cnx_t* cnx,
@ -501,6 +504,17 @@ int slipstream_client_callback(picoquic_cnx_t* cnx,
break;
case picoquic_callback_ready:
fprintf(stdout, "Connection confirmed.\n");
// add rest of the resolvers
for (size_t i = 1; i < client_ctx->server_address_count; i++) {
struct sockaddr* server_address = (struct sockaddr*)&client_ctx->server_addresses[i];
uint64_t current_time = picoquic_current_time();
ret = picoquic_probe_new_path(cnx, server_address, NULL, current_time);
if (ret != 0) {
fprintf(stderr, "Could not create probe new path\n");
return -1;
}
}
break;
default:
/* unexpected -- just ignore. */
@ -514,34 +528,35 @@ void client_sighandler(int signum) {
printf("Signal %d received\n", signum);
}
static int slipstream_connect(char const* server_name, int server_port,
static int slipstream_connect(struct sockaddr_storage* server_address,
picoquic_quic_t* quic, picoquic_cnx_t** cnx,
slipstream_client_ctx_t* client_ctx) {
int ret = 0;
char const* sni = SLIPSTREAM_SNI;
uint64_t current_time = picoquic_current_time();
struct sockaddr_storage server_address;
*cnx = NULL;
/* Get the server's address */
int is_name = 0;
ret = picoquic_get_server_address(server_name, server_port, &server_address, &is_name);
char host[NI_MAXHOST];
socklen_t addrlen = sizeof(*server_address);
ret = getnameinfo((struct sockaddr*)server_address, addrlen,
host, sizeof(host),
NULL, 0,
NI_NUMERICHOST | NI_NUMERICSERV);
if (ret != 0) {
fprintf(stderr, "Cannot get the IP address for <%s> port <%d>", server_name, server_port);
fprintf(stderr, "Could not get name info for server address\n");
return -1;
}
sni = server_name;
/* Initialize the callback context and create the connection context.
* We use minimal options on the client side, keeping the transport
* parameter values set by default for picoquic. This could be fixed later.
*/
printf("Starting connection to %s, port %d\n", server_name, server_port);
printf("Starting connection to %s\n", host);
/* Create a client connection */
*cnx = picoquic_create_cnx(quic, picoquic_null_connection_id, picoquic_null_connection_id,
(struct sockaddr*)&server_address, current_time, 0, sni, SLIPSTREAM_ALPN, 1);
(struct sockaddr*)server_address, current_time, 0, sni, SLIPSTREAM_ALPN, 1);
if (*cnx == NULL) {
fprintf(stderr, "Could not create connection context\n");
return -1;
@ -569,12 +584,10 @@ static int slipstream_connect(char const* server_name, int server_port,
return ret;
}
int picoquic_slipstream_client(int listen_port, char const* server_name, int server_port, const char* domain_name) {
int picoquic_slipstream_client(int listen_port, char const* resolver_addresses_filename, const char* domain_name) {
/* Start: start the QUIC process */
int ret = 0;
picoquic_quic_t* quic = NULL;
uint64_t current_time = 0;
picoquic_cnx_t* cnx = NULL;
char const* ticket_store_filename = SLIPSTREAM_CLIENT_TICKET_STORE;
char const* token_store_filename = SLIPSTREAM_CLIENT_TOKEN_STORE;
@ -593,12 +606,11 @@ int picoquic_slipstream_client(int listen_port, char const* server_name, int ser
#ifdef BUILD_LOGLIB
config.qlog_dir = SLIPSTREAM_QLOG_DIR;
#endif
config.server_port = server_port;
config.mtu_max = mtu;
config.initial_send_mtu_ipv4 = mtu;
config.initial_send_mtu_ipv6 = mtu;
config.cc_algo_id = "cubic";
config.multipath_option = 0;
config.multipath_option = 1;
config.use_long_log = 1;
config.do_preemptive_repeat = 1;
config.disable_port_blocking = 1;
@ -612,7 +624,7 @@ int picoquic_slipstream_client(int listen_port, char const* server_name, int ser
slipstream_client_ctx_t *client_ctx = malloc(sizeof(slipstream_client_ctx_t));
memset(client_ctx, 0, sizeof(slipstream_client_ctx_t));
/* Create QUIC context */
quic = picoquic_create_and_configure(&config, slipstream_client_callback, client_ctx, current_time, NULL);
picoquic_quic_t* quic = picoquic_create_and_configure(&config, slipstream_client_callback, client_ctx, current_time, NULL);
if (quic == NULL) {
fprintf(stderr, "Could not create server context\n");
return -1;
@ -625,7 +637,15 @@ int picoquic_slipstream_client(int listen_port, char const* server_name, int ser
#endif
picoquic_set_key_log_file_from_env(quic);
ret = slipstream_connect(server_name, server_port, quic, &cnx, client_ctx);
/* Read the server address list from the file */
client_ctx->server_addresses = read_resolver_addresses(resolver_addresses_filename, &client_ctx->server_address_count);
if (!client_ctx->server_addresses) {
printf("Failed to read IP addresses\n");
return 1;
}
picoquic_cnx_t* cnx = NULL;
ret = slipstream_connect(client_ctx->server_addresses, quic, &cnx, client_ctx);
if (ret != 0) {
fprintf(stderr, "Could not connect to server\n");
return -1;

View file

@ -0,0 +1,83 @@
#include "slipstream_resolver_addresses.h"
#include <stdlib.h>
#include <string.h>
#include <picosocks.h>
#define MAX_IP_LENGTH 20
#define INITIAL_CAPACITY 10
#define MAX_LINE_LENGTH 50
#define DEFAULT_PORT 53
struct sockaddr_storage* read_resolver_addresses(const char *resolver_addresses_filename, size_t *count) {
*count = 0;
FILE *fp = fopen(resolver_addresses_filename, "r");
if (!fp) {
return NULL;
}
int capacity = INITIAL_CAPACITY;
struct sockaddr_storage* server_address = calloc(capacity, sizeof(struct sockaddr_storage));
if (!server_address) {
fclose(fp);
return NULL;
}
char line[MAX_LINE_LENGTH];
int valid_addresses = 0;
while (fgets(line, MAX_LINE_LENGTH, fp)) {
// Remove newline
line[strcspn(line, "\n")] = '\0';
// Skip empty or whitespace-only lines
if (strlen(line) == 0 || strspn(line, " \t") == strlen(line)) {
continue;
}
// Resize array if needed
if (valid_addresses == capacity) {
capacity *= 2;
struct sockaddr_storage* temp = realloc(server_address, capacity * sizeof(struct sockaddr_storage));
if (!temp) {
fprintf(stderr, "Memory allocation failed\n");
free(server_address);
fclose(fp);
return NULL;
}
server_address = temp;
}
char server_name[MAX_IP_LENGTH];
int server_port = DEFAULT_PORT;
// Parse line for IP and optional port
if (sscanf(line, "%s %d", server_name, &server_port) < 1) {
continue; // Invalid format
}
printf("Adding %s:%d\n", server_name, server_port);
int is_name = 0;
if (picoquic_get_server_address(server_name, server_port, &server_address[valid_addresses], &is_name) != 0) {
fprintf(stderr, "Cannot get the IP address for <%s> port <%d>\n", server_name, server_port);
continue; // Skip invalid addresses instead of failing
}
valid_addresses++;
}
fclose(fp);
*count = valid_addresses;
// Trim excess memory if needed
if (valid_addresses < capacity) {
struct sockaddr_storage* temp = realloc(server_address, valid_addresses * sizeof(struct sockaddr_storage));
if (temp) {
server_address = temp;
}
}
return server_address;
}

View file

@ -489,7 +489,6 @@ int picoquic_slipstream_server(int server_port, const char* server_cert, const c
char const* upstream_name, int upstream_port, const char* domain_name) {
/* Start: start the QUIC process with cert and key files */
int ret = 0;
picoquic_quic_t* quic = NULL;
uint64_t current_time = 0;
slipstream_server_ctx_t default_context = {0};
printf("Starting Picoquic Sample server on port %d\n", server_port);
@ -518,7 +517,7 @@ int picoquic_slipstream_server(int server_port, const char* server_cert, const c
config.initial_send_mtu_ipv4 = mtu;
config.initial_send_mtu_ipv6 = mtu;
config.cc_algo_id = "cubic";
config.multipath_option = 0;
config.multipath_option = 1;
config.use_long_log = 1;
config.do_preemptive_repeat = 1;
config.disable_port_blocking = 1;
@ -529,7 +528,7 @@ int picoquic_slipstream_server(int server_port, const char* server_cert, const c
/* Create the QUIC context for the server */
current_time = picoquic_current_time();
/* Create QUIC context */
quic = picoquic_create_and_configure(&config, slipstream_server_callback, &default_context, current_time, NULL);
picoquic_quic_t* quic = picoquic_create_and_configure(&config, slipstream_server_callback, &default_context, current_time, NULL);
if (quic == NULL) {
fprintf(stderr, "Could not create server context\n");
return -1;