diff --git a/include/slipstream.h b/include/slipstream.h index 8288f5c..852fc12 100644 --- a/include/slipstream.h +++ b/include/slipstream.h @@ -23,7 +23,7 @@ typedef struct st_address_t { } address_t; int picoquic_slipstream_client(int listen_port, struct st_address_t* server_addresses, size_t server_address_count, const char* domain_name, - const char* cc_algo_id, bool gso); + const char* cc_algo_id, bool gso, size_t keep_alive_interval); int picoquic_slipstream_server(int server_port, const char* pem_cert, const char* pem_key, struct sockaddr_storage* target_address, const char* domain_name); diff --git a/src/slipstream_client.c b/src/slipstream_client.c index 3e91ded..d893056 100644 --- a/src/slipstream_client.c +++ b/src/slipstream_client.c @@ -658,9 +658,6 @@ static int slipstream_connect(struct sockaddr_storage* server_address, return -1; } - // 400ms - picoquic_enable_keep_alive(*cnx, 400000); - /* Document connection in client's context */ client_ctx->cnx = *cnx; /* Set the client callback context */ @@ -683,7 +680,7 @@ static int slipstream_connect(struct sockaddr_storage* server_address, return ret; } -int picoquic_slipstream_client(int listen_port, struct st_address_t* server_addresses, size_t server_address_count, const char* domain_name, const char* cc_algo_id, bool gso) { +int picoquic_slipstream_client(int listen_port, struct st_address_t* server_addresses, size_t server_address_count, const char* domain_name, const char* cc_algo_id, bool gso, const size_t keep_alive_interval) { /* Start: start the QUIC process */ int ret = 0; uint64_t current_time = 0; @@ -747,6 +744,12 @@ int picoquic_slipstream_client(int listen_port, struct st_address_t* server_addr return -1; } + if (keep_alive_interval != 0) { + picoquic_enable_keep_alive(cnx, keep_alive_interval * 1000); + } else { + picoquic_disable_keep_alive(cnx); + } + // Create listening socket client_ctx.listen_sock = socket(AF_INET, SOCK_STREAM, 0); if (client_ctx.listen_sock < 0) { diff --git a/src/slipstream_client_cli.c b/src/slipstream_client_cli.c index 94a5345..bfa0057 100644 --- a/src/slipstream_client_cli.c +++ b/src/slipstream_client_cli.c @@ -22,6 +22,7 @@ static struct argp_option options[] = { {"congestion-control", 'c', "ALGO", 0, "Congestion control algorithm (bbr, dcubic) (default: dcubic)", 0}, {"gso", 'g', "BOOL", OPTION_ARG_OPTIONAL, "GSO enabled (true/false) (default: false). Use --gso or --gso=true to enable.", 0}, {"domain", 'd', "DOMAIN", 0, "Domain name used for the covert channel (Required)", 0}, + {"keep-alive-interval", 't', "MS", 0, "Send keep alive pings at this interval (default: 400, disabled: 0)", 0}, {0} // End of options }; @@ -33,6 +34,7 @@ struct arguments { size_t resolver_count; char* cc_algo_id; bool gso; + size_t keep_alive_interval; }; /* Client mode parser */ @@ -97,6 +99,13 @@ static error_t parse_opt(int key, char* arg, struct argp_state* state) { argp_error(state, "Invalid boolean value for --gso: '%s'. Use 'true' or 'false'.", arg); } break; + case 't': + arguments->keep_alive_interval = atoi(arg); + if (arguments->keep_alive_interval < 0) { + argp_error(state, "Invalid keep alive interval: %s", arg); + } + break; + case ARGP_KEY_ARG: // No positional arguments expected argp_usage(state); @@ -130,6 +139,7 @@ int main(int argc, char** argv) { arguments.gso = false; // Default GSO state arguments.resolver_addresses = NULL; arguments.resolver_count = 0; + arguments.keep_alive_interval = 400; // Default keep alive interval // Ensure output buffers are flushed immediately (useful for debugging/logging) setbuf(stdout, NULL); @@ -165,7 +175,8 @@ int main(int argc, char** argv) { arguments.resolver_count, arguments.domain_name, arguments.cc_algo_id, - arguments.gso + arguments.gso, + arguments.keep_alive_interval ); // Free allocated memory for resolver addresses