diff --git a/CMakeLists.txt b/CMakeLists.txt index 3fab895d..b2e64f7d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,11 @@ INCLUDE(CMakePushCheckState) INCLUDE(CheckCSourceCompiles) INCLUDE(deps/picotls/cmake/dtrace-utils.cmake) +if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + # on Darwin, try and pick up openssl from homebrew + set(CMAKE_PREFIX_PATH /usr/local/opt/openssl@1.1 /usr/local/opt/openssl) +endif() + FIND_PACKAGE(OpenSSL REQUIRED) IF (OPENSSL_FOUND AND (OPENSSL_VERSION VERSION_LESS "1.0.2")) MESSAGE(FATAL "OpenSSL 1.0.2 or above is missing") diff --git a/deps/picotls b/deps/picotls index 4e57e9b0..8bd23e83 160000 --- a/deps/picotls +++ b/deps/picotls @@ -1 +1 @@ -Subproject commit 4e57e9b09ebac4da4c28433e20e5a88ffa972a08 +Subproject commit 8bd23e831de9181db1e8cdd9bba191a28d78c388 diff --git a/include/quicly.h b/include/quicly.h index 9ddbdb2c..86d361a3 100644 --- a/include/quicly.h +++ b/include/quicly.h @@ -911,7 +911,9 @@ uint32_t quicly_num_streams_by_group(quicly_conn_t *conn, int uni, int locally_i /** * */ +#if defined(QUICLY_CLIENT) == defined(QUICLY_SERVER) static int quicly_is_client(quicly_conn_t *conn); +#endif /** * */ @@ -1260,9 +1262,10 @@ void quicly_stream_noop_on_receive_reset(quicly_stream_t *stream, int err); extern const quicly_stream_callbacks_t quicly_stream_noop_callbacks; +#ifndef NO_LOG #define QUICLY_LOG_CONN(_type, _conn, _block) \ do { \ - if (!ptls_log.is_active) \ + if (!PTLS_LOG_IS_ACTIVE(ptls_log)) \ break; \ quicly_conn_t *_c = (_conn); \ if (ptls_skip_tracing(_c->crypto.tls)) \ @@ -1275,6 +1278,9 @@ extern const quicly_stream_callbacks_t quicly_stream_noop_callbacks; } while (0); \ }); \ } while (0) +#else +#define QUICLY_LOG_CONN(...) +#endif /* inline definitions */ @@ -1332,11 +1338,18 @@ inline const quicly_transport_parameters_t *quicly_get_remote_transport_paramete return &c->remote.transport_params; } +#if defined(QUICLY_CLIENT) && !defined(QUICLY_SERVER) +#define quicly_is_client(x) (1) +#elif !defined(QUICLY_CLIENT) && defined(QUICLY_SERVER) +#define quicly_is_client(x) (0) +#else inline int quicly_is_client(quicly_conn_t *conn) { struct _st_quicly_conn_public_t *c = (struct _st_quicly_conn_public_t *)conn; return (c->local.bidi.next_stream_id & 1) == 0; } +#endif + inline quicly_stream_id_t quicly_get_local_next_stream_id(quicly_conn_t *conn, int uni) { diff --git a/lib/defaults.c b/lib/defaults.c index 4a3aeded..1110e18e 100644 --- a/lib/defaults.c +++ b/lib/defaults.c @@ -20,6 +20,11 @@ * IN THE SOFTWARE. */ #include + +#ifdef PARTICLE +#include +#endif + #include "quicly/defaults.h" #define DEFAULT_INITIAL_EGRESS_MAX_UDP_PAYLOAD_SIZE 1280 @@ -364,6 +369,9 @@ void quicly_default_free_stream(quicly_stream_t *stream) static int64_t default_now(quicly_now_t *self) { +#if defined(PARTICLE) + return HAL_Timer_Get_Milli_Seconds(); +#else struct timeval tv; gettimeofday(&tv, NULL); int64_t tv_now = (int64_t)tv.tv_sec * 1000 + tv.tv_usec / 1000; @@ -373,6 +381,7 @@ static int64_t default_now(quicly_now_t *self) if (now < tv_now) now = tv_now; return now; +#endif } quicly_now_t quicly_default_now = {default_now}; diff --git a/lib/quicly.c b/lib/quicly.c index 32a3470b..fac7091e 100644 --- a/lib/quicly.c +++ b/lib/quicly.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "khash.h" #include "quicly.h" #include "quicly/defaults.h" @@ -559,6 +560,7 @@ static inline uint8_t get_epoch(uint8_t first_byte) return QUICLY_EPOCH_0RTT; default: assert(!"FIXME"); + abort(); } } @@ -2154,7 +2156,16 @@ static quicly_conn_t *create_connection(quicly_context_t *ctx, uint32_t protocol assert(ctx->receive_datagram_frame != NULL); /* create TLS context */ - if ((tls = ptls_new(ctx->tls, server_name == NULL)) == NULL) +#if defined(QUICLY_CLIENT) && !defined(QUICLY_SERVER) + assert(server_name != 0); + tls = ptls_client_new(ctx->tls); +#elif !defined(QUICLY_CLIENT) && defined(QUICLY_SERVER) + assert(server_name == 0); + tls = ptls_server_new(ctx->tls); +#else + tls = ptls_new(ctx->tls, server_name == NULL); +#endif + if (tls == NULL) return NULL; if (server_name != NULL && ptls_set_server_name(tls, server_name, strlen(server_name)) != 0) { ptls_free(tls); @@ -2252,7 +2263,15 @@ static int client_collected_extensions(ptls_t *tls, ptls_handshake_properties_t assert(slots[1].type == UINT16_MAX); const uint8_t *src = slots[0].data.base, *end = src + slots[0].data.len; +#ifdef PTLS_MINIMIZE_STACK + quicly_transport_parameters_t *tmp_params __attribute__((__cleanup__(ptls_cleanup_free))) = + malloc(sizeof(quicly_transport_parameters_t)); + if (tmp_params == NULL) + return PTLS_ERROR_NO_MEMORY; +#define params (*tmp_params) +#else quicly_transport_parameters_t params; +#endif quicly_cid_t original_dcid, initial_scid, retry_scid = {}; /* obtain pointer to initial CID of the peer. It is guaranteed to exist in the first slot, as TP is received before any frame @@ -2308,6 +2327,7 @@ static int client_collected_extensions(ptls_t *tls, ptls_handshake_properties_t Exit: return ret; /* negative error codes used to transmit QUIC errors through picotls */ +#undef params } int quicly_connect(quicly_conn_t **_conn, quicly_context_t *ctx, const char *server_name, struct sockaddr *dest_addr, @@ -4083,17 +4103,29 @@ static int send_data_blocked(quicly_conn_t *conn, quicly_send_context_t *s) static int send_resumption_token(quicly_conn_t *conn, quicly_send_context_t *s) { +#ifdef PTLS_MINIMIZE_STACK + quicly_address_token_plaintext_t *tmp_token __attribute__((__cleanup__(ptls_cleanup_free))) = + calloc(1, sizeof(quicly_address_token_plaintext_t)); + if (tmp_token == NULL) + return SIZE_MAX; +#define token (*tmp_token) +#else quicly_address_token_plaintext_t token; +#endif ptls_buffer_t tokenbuf; - uint8_t tokenbuf_small[128]; quicly_sent_t *sent; int ret; +#ifdef PTLS_MINIMIZE_STACK + ptls_buffer_init(&tokenbuf, "", 0); +#else + uint8_t tokenbuf_small[128]; ptls_buffer_init(&tokenbuf, tokenbuf_small, sizeof(tokenbuf_small)); +#endif /* build token */ - token = - (quicly_address_token_plaintext_t){QUICLY_ADDRESS_TOKEN_TYPE_RESUMPTION, conn->super.ctx->now->cb(conn->super.ctx->now)}; + token.type = QUICLY_ADDRESS_TOKEN_TYPE_RESUMPTION; + token.issued_at = conn->super.ctx->now->cb(conn->super.ctx->now); token.remote = conn->super.remote.address; /* TODO fill token.resumption */ @@ -4123,6 +4155,7 @@ static int send_resumption_token(quicly_conn_t *conn, quicly_send_context_t *s) Exit: ptls_buffer_dispose(&tokenbuf); return ret; +#undef token } size_t quicly_send_version_negotiation(quicly_context_t *ctx, ptls_iovec_t dest_cid, ptls_iovec_t src_cid, const uint32_t *versions, @@ -4185,14 +4218,23 @@ size_t quicly_send_retry(quicly_context_t *ctx, ptls_aead_context_t *token_encry ptls_iovec_t odcid, ptls_iovec_t token_prefix, ptls_iovec_t appdata, ptls_aead_context_t **retry_aead_cache, uint8_t *datagram) { +#ifdef PTLS_MINIMIZE_STACK + quicly_address_token_plaintext_t *tmp_token __attribute__((__cleanup__(ptls_cleanup_free))) = + calloc(1, sizeof(quicly_address_token_plaintext_t)); + if (tmp_token == NULL) + return SIZE_MAX; +#define token (*tmp_token) +#else quicly_address_token_plaintext_t token; +#endif ptls_buffer_t buf; int ret; assert(!(src_cid.len == odcid.len && memcmp(src_cid.base, odcid.base, src_cid.len) == 0)); /* build token as plaintext */ - token = (quicly_address_token_plaintext_t){QUICLY_ADDRESS_TOKEN_TYPE_RETRY, ctx->now->cb(ctx->now)}; + token.type = QUICLY_ADDRESS_TOKEN_TYPE_RETRY; + token.issued_at = ctx->now->cb(ctx->now); set_address(&token.remote, dest_addr); set_address(&token.local, src_addr); @@ -4249,6 +4291,7 @@ size_t quicly_send_retry(quicly_context_t *ctx, ptls_aead_context_t *token_encry Exit: return ret == 0 ? buf.off : SIZE_MAX; +#undef token } static struct st_quicly_pn_space_t *setup_send_space(quicly_conn_t *conn, size_t epoch, quicly_send_context_t *s) @@ -4501,7 +4544,7 @@ static int update_traffic_key_cb(ptls_update_traffic_key_t *self, ptls_t *tls, i } break; default: assert(!"logic flaw"); - break; + abort(); } #undef SELECT_CIPHER_CONTEXT @@ -4806,12 +4849,23 @@ int quicly_set_cc(quicly_conn_t *conn, quicly_cc_type_t *cc) int quicly_send(quicly_conn_t *conn, quicly_address_t *dest, quicly_address_t *src, struct iovec *datagrams, size_t *num_datagrams, void *buf, size_t bufsize) { - quicly_send_context_t s = {.current = {.first_byte = -1}, - .datagrams = datagrams, - .max_datagrams = *num_datagrams, - .payload_buf = {.datagram = buf, .end = (uint8_t *)buf + bufsize}, - .first_packet_number = conn->egress.packet_number}; int ret; +#ifdef PTLS_MINIMIZE_STACK + quicly_send_context_t *tmp_s __attribute__((__cleanup__(ptls_cleanup_free))) = calloc(1, sizeof(quicly_send_context_t)); + if (tmp_s == NULL) + return PTLS_ERROR_NO_MEMORY; + +#define s (*tmp_s) +#else + quicly_send_context_t s; +#endif + + s.current.first_byte = -1; + s.datagrams = datagrams; + s.max_datagrams = *num_datagrams; + s.payload_buf.datagram = buf; + s.payload_buf.end = (uint8_t *)buf + bufsize; + s.first_packet_number = conn->egress.packet_number; lock_now(conn, 0); @@ -4875,6 +4929,7 @@ int quicly_send(quicly_conn_t *conn, quicly_address_t *dest, quicly_address_t *s *num_datagrams = s.num_datagrams; unlock_now(conn); return ret; +#undef s } size_t quicly_send_close_invalid_token(quicly_context_t *ctx, uint32_t protocol_version, ptls_iovec_t dest_cid, @@ -5144,7 +5199,14 @@ static int handle_reset_stream_frame(quicly_conn_t *conn, struct st_quicly_handl static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload_state_t *state) { +#ifdef PTLS_MINIMIZE_STACK + quicly_ack_frame_t *tmp_frame __attribute__((__cleanup__(ptls_cleanup_free))) = malloc(sizeof(quicly_ack_frame_t)); + if (tmp_frame == NULL) + return PTLS_ERROR_NO_MEMORY; +#define frame (*tmp_frame) +#else quicly_ack_frame_t frame; +#endif quicly_sentmap_iter_t iter; struct { uint64_t pn; @@ -5285,6 +5347,7 @@ static int handle_ack_frame(quicly_conn_t *conn, struct st_quicly_handle_payload setup_next_send(conn); return 0; +#undef frame } static int handle_max_stream_data_frame(quicly_conn_t *conn, struct st_quicly_handle_payload_state_t *state) @@ -5675,7 +5738,14 @@ int handle_close(quicly_conn_t *conn, int err, uint64_t frame_type, ptls_iovec_t static int handle_transport_close_frame(quicly_conn_t *conn, struct st_quicly_handle_payload_state_t *state) { +#ifdef PTLS_MINIMIZE_STACK + quicly_transport_close_frame_t *tmp_frame __attribute__((__cleanup__(ptls_cleanup_free))) = malloc(sizeof(quicly_transport_close_frame_t)); + if (tmp_frame == NULL) + return PTLS_ERROR_NO_MEMORY; +#define frame (*tmp_frame) +#else quicly_transport_close_frame_t frame; +#endif int ret; if ((ret = quicly_decode_transport_close_frame(&state->src, state->end, &frame)) != 0) @@ -5689,6 +5759,7 @@ static int handle_transport_close_frame(quicly_conn_t *conn, struct st_quicly_ha PTLS_LOG_ELEMENT_UNSAFESTR(reason_phrase, (const char *)frame.reason_phrase.base, frame.reason_phrase.len); }); return handle_close(conn, QUICLY_ERROR_FROM_TRANSPORT_ERROR_CODE(frame.error_code), frame.frame_type, frame.reason_phrase); +#undef frame } static int handle_application_close_frame(quicly_conn_t *conn, struct st_quicly_handle_payload_state_t *state) @@ -6012,7 +6083,13 @@ static int handle_stateless_reset(quicly_conn_t *conn) static int validate_retry_tag(quicly_decoded_packet_t *packet, quicly_cid_t *odcid, ptls_aead_context_t *retry_aead) { size_t pseudo_packet_len = 1 + odcid->len + packet->encrypted_off; +#ifdef PTLS_MINIMIZE_STACK + uint8_t *pseudo_packet __attribute__((__cleanup__(ptls_cleanup_free))) = malloc(pseudo_packet_len); + if (pseudo_packet == NULL) + return PTLS_ERROR_NO_MEMORY; +#else uint8_t pseudo_packet[pseudo_packet_len]; +#endif pseudo_packet[0] = odcid->len; memcpy(pseudo_packet + 1, odcid->cid, odcid->len); memcpy(pseudo_packet + 1 + odcid->len, packet->octets.base, packet->encrypted_off); @@ -6615,7 +6692,7 @@ int quicly_encrypt_address_token(void (*random_bytes)(void *, size_t), ptls_aead break; default: assert(!"unsupported address type"); - break; + abort(); } }); ptls_buffer_push16(buf, port); @@ -6654,7 +6731,13 @@ int quicly_decrypt_address_token(ptls_aead_context_t *aead, quicly_address_token size_t len, size_t prefix_len, const char **err_desc) { const uint8_t *const token = _token; +#ifdef PTLS_MINIMIZE_STACK + uint8_t *ptbuf __attribute__((__cleanup__(ptls_cleanup_free))) = malloc(QUICLY_MIN_CLIENT_INITIAL_SIZE); + if (ptbuf == NULL) + return PTLS_ERROR_NO_MEMORY; +#else uint8_t ptbuf[QUICLY_MIN_CLIENT_INITIAL_SIZE]; +#endif size_t ptlen; *err_desc = NULL; @@ -6664,7 +6747,7 @@ int quicly_decrypt_address_token(ptls_aead_context_t *aead, quicly_address_token *err_desc = "token too small"; return PTLS_ALERT_DECODE_ERROR; } - if (prefix_len + 1 + aead->algo->iv_size + sizeof(ptbuf) + aead->algo->tag_size < len) { + if (prefix_len + 1 + aead->algo->iv_size + QUICLY_MIN_CLIENT_INITIAL_SIZE + aead->algo->tag_size < len) { *err_desc = "token too large"; return PTLS_ALERT_DECODE_ERROR; } @@ -6837,19 +6920,25 @@ const quicly_stream_callbacks_t quicly_stream_noop_callbacks = { void quicly__debug_printf(quicly_conn_t *conn, const char *function, int line, const char *fmt, ...) { -#if QUICLY_USE_DTRACE +#if QUICLY_USE_DTRACE || (defined(PARTICLE) && defined(QUICLY_USE_TRACER)) char buf[1024]; va_list args; +#if !defined(PARTICLE) if (!QUICLY_DEBUG_MESSAGE_ENABLED()) return; +#endif va_start(args, fmt); vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); +#if defined(PARTICLE) && defined(QUICLY_USE_TRACER) + QUICLY_TRACER_DEBUG_MESSAGE(conn, function, line, buf); +#else QUICLY_DEBUG_MESSAGE(conn, function, line, buf); #endif +#endif } const uint32_t quicly_supported_versions[] = {QUICLY_PROTOCOL_VERSION_1, QUICLY_PROTOCOL_VERSION_DRAFT29, diff --git a/misc/probe2trace.pl b/misc/probe2trace.pl index 7b9465cc..222fd040 100755 --- a/misc/probe2trace.pl +++ b/misc/probe2trace.pl @@ -74,6 +74,17 @@ EOT } elsif ($arch eq 'darwin') { +} elsif ($arch eq 'particle') { + print << 'EOT'; +#ifndef particle_probes_h +#define particle_probes_h + +#include + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" + +EOT } elsif ($arch eq 'embedded') { print << 'EOT'; #ifndef embedded_probes_h @@ -131,12 +142,21 @@ my @fields; push @fields, map {["rtt.$_" => '%u']} qw(minimum smoothed variance); push @fields, map {["cc.$_" => '%u']} qw(cwnd ssthresh cwnd_initial cwnd_exiting_slow_start cwnd_minimum cwnd_maximum num_loss_episodes); - push @fields, map {["num_packets.$_" => $arch eq 'embedded' ? '%" PRIu64 "' : '%llu']} qw(sent ack_received lost lost_time_threshold late_acked received decryption_failed); - push @fields, map {["num_bytes.$_" => $arch eq 'embedded' ? '%" PRIu64 "' : '%llu']} qw(sent received); - for my $container (qw(num_frames_sent num_frames_received)) { - push @fields, map{["$container.$_" => $arch eq 'embedded' ? '%" PRIu64 "' : '%llu']} qw(padding ping ack reset_stream stop_sending crypto new_token stream max_data max_stream_data max_streams_bidi max_streams_uni data_blocked stream_data_blocked streams_blocked new_connection_id retire_connection_id path_challenge path_response transport_close application_close handshake_done ack_frequency); + if ($arch eq 'particle') { + push @fields, map {["num_packets.$_" => '%u']} qw(sent ack_received lost lost_time_threshold late_acked received decryption_failed); + push @fields, map {["num_bytes.$_" => '%u']} qw(sent received); + for my $container (qw(num_frames_sent num_frames_received)) { + push @fields, map{["$container.$_" => '%u']} qw(padding ping ack reset_stream stop_sending crypto new_token stream max_data max_stream_data max_streams_bidi max_streams_uni data_blocked stream_data_blocked streams_blocked new_connection_id retire_connection_id path_challenge path_response transport_close application_close handshake_done ack_frequency); + } + push @fields, ["num_ptos" => '%u']; + } else { + push @fields, map {["num_packets.$_" => $arch eq 'embedded' ? '%" PRIu64 "' : '%llu']} qw(sent ack_received lost lost_time_threshold late_acked received decryption_failed); + push @fields, map {["num_bytes.$_" => $arch eq 'embedded' ? '%" PRIu64 "' : '%llu']} qw(sent received); + for my $container (qw(num_frames_sent num_frames_received)) { + push @fields, map{["$container.$_" => $arch eq 'embedded' ? '%" PRIu64 "' : '%llu']} qw(padding ping ack reset_stream stop_sending crypto new_token stream max_data max_stream_data max_streams_bidi max_streams_uni data_blocked stream_data_blocked streams_blocked new_connection_id retire_connection_id path_challenge path_response transport_close application_close handshake_done ack_frequency); + } + push @fields, ["num_ptos" => $arch eq 'embedded' ? '%" PRIu64 "' : '%llu']; } - push @fields, ["num_ptos" => $arch eq 'embedded' ? '%" PRIu64 "' : '%llu']; # generate @fmt, @ap push @fmt, map {my $n = $_->[0]; $n =~ tr/./_/; sprintf '"%s":%s', $n, $_->[1]} @fields; if ($arch eq 'linux') { @@ -164,12 +184,18 @@ } elsif ($arch eq 'darwin') { push @fmt, qq!"$name":\%lu!; push @ap, "(uint64_t)arg$i"; + } elsif ($arch eq 'particle') { + push @fmt, qq!"$name":\%u!; + push @ap, "(uint32_t)arg$i"; } else { push @fmt, qq!"$name":\%llu!; push @ap, "(unsigned long long)arg$i"; } } elsif ($type =~ /^int(?:([0-9]+)_t|)$/) { - if ($arch ne 'embedded' && $arch ne 'tracer') { + if ($arch eq 'particle') { + push @fmt, qq!"$name":\%@{[$1 && $1 == 64 ? 'd' : 'd']}!; + push @ap, "(uint32_t)arg$i"; + } elsif ($arch ne 'embedded' && $arch ne 'tracer') { push @fmt, qq!"$name":\%@{[$1 && $1 == 64 ? 'ld' : 'd']}!; push @ap, "arg$i"; } else { @@ -187,8 +213,13 @@ } } elsif ($type =~ /\s+\*$/) { # emit the address for other pointers - push @fmt, qq!"$name":"0x%llx"!; - push @ap, "(unsigned long long)arg$i"; + if ($arch eq 'particle') { + push @fmt, qq!"$name":"0x%x"!; + push @ap, "arg$i"; + } else { + push @fmt, qq!"$name":"0x%llx"!; + push @ap, "(unsigned long long)arg$i"; + } } else { die "can't handle type: $type"; } @@ -247,6 +278,14 @@ { fprintf(quicly_trace_fp, "{$fmt}\\n", @{[join ', ', @ap]}); } +EOT + } elsif ($arch eq 'particle') { + print << "EOT"; + +static void __attribute__((noinline)) QUICLY_TRACER_@{[ uc $probe->[0] ]}($params) +{ + LOG_PRINTF(INFO, "{$fmt}\\n", @{[join ', ', @ap]}); +} EOT } else { # callback probes, the ones not specified are no-op @@ -272,6 +311,12 @@ if ($arch eq 'embedded' || $arch eq 'tracer') { print << 'EOT'; +#endif +EOT +} elsif ($arch eq 'particle') { +print << 'EOT'; + +#pragma GCC diagnostic pop #endif EOT } diff --git a/particle/.gitignore b/particle/.gitignore new file mode 100644 index 00000000..53388319 --- /dev/null +++ b/particle/.gitignore @@ -0,0 +1,2 @@ +src/quicly-tracer.h +target diff --git a/particle/.vscode/launch.json b/particle/.vscode/launch.json new file mode 100644 index 00000000..b9192d1d --- /dev/null +++ b/particle/.vscode/launch.json @@ -0,0 +1,77 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "cortex-debug", + "request": "attach", + "servertype": "openocd", + "name": "Particle Debugger", + "cwd": "${workspaceRoot}", + "armToolchainPath": "${command:particle.getDebuggerCompilerDir}", + "executable": "${command:particle.getDebuggerExecutable}", + "serverpath": "${command:particle.getDebuggerOpenocdPath}", + "preLaunchTask": "Particle: Flash application for debug (local)", + "searchDir": [ + "${command:particle.getDebuggerSearchDir}" + ], + "configFiles": [ + "${command:particle.getDebuggerConfigFiles}" + ], + "postAttachCommands": [ + "${command:particle.getDebuggerPostAttachCommands}" + ], + "particle": { + "version": "1.0.0", + "debugger": "particle-debugger" + } + }, + { + "type": "cortex-debug", + "request": "attach", + "servertype": "openocd", + "name": "Particle Programmer Shield", + "cwd": "${workspaceRoot}", + "armToolchainPath": "${command:particle.getDebuggerCompilerDir}", + "executable": "${command:particle.getDebuggerExecutable}", + "serverpath": "${command:particle.getDebuggerOpenocdPath}", + "preLaunchTask": "Particle: Flash application for debug (local)", + "searchDir": [ + "${command:particle.getDebuggerSearchDir}" + ], + "configFiles": [ + "${command:particle.getDebuggerConfigFiles}" + ], + "postAttachCommands": [ + "${command:particle.getDebuggerPostAttachCommands}" + ], + "particle": { + "version": "1.0.0", + "debugger": "particle-programmer-shield" + } + }, + { + "type": "cortex-debug", + "request": "attach", + "servertype": "openocd", + "name": "Generic DAPLink Compatible Debugger", + "cwd": "${workspaceRoot}", + "armToolchainPath": "${command:particle.getDebuggerCompilerDir}", + "executable": "${command:particle.getDebuggerExecutable}", + "serverpath": "${command:particle.getDebuggerOpenocdPath}", + "preLaunchTask": "Particle: Flash application for debug (local)", + "searchDir": [ + "${command:particle.getDebuggerSearchDir}" + ], + "configFiles": [ + "${command:particle.getDebuggerConfigFiles}" + ], + "postAttachCommands": [ + "${command:particle.getDebuggerPostAttachCommands}" + ], + "particle": { + "version": "1.0.0", + "debugger": "generic-cmsis-dap" + } + } + ] +} diff --git a/particle/.vscode/settings.json b/particle/.vscode/settings.json new file mode 100644 index 00000000..99d61868 --- /dev/null +++ b/particle/.vscode/settings.json @@ -0,0 +1,9 @@ +{ + "extensions.ignoreRecommendations": true, + "C_Cpp.default.configurationProvider": "particle.particle-vscode-core", + "files.associations": { + "*.ino": "cpp" + }, + "particle.targetPlatform": "argon", + "particle.firmwareVersion": "5.2.0" +} diff --git a/particle/project.properties b/particle/project.properties new file mode 100644 index 00000000..46a8befb --- /dev/null +++ b/particle/project.properties @@ -0,0 +1 @@ +name=particle diff --git a/particle/src/build.mk b/particle/src/build.mk new file mode 100644 index 00000000..b6466225 --- /dev/null +++ b/particle/src/build.mk @@ -0,0 +1,65 @@ +# .PHONY: +# $(SOURCE_PATH)/../misc/probe2trace.pl -a particle < $(SOURCE_PATH)/../quicly-probes.d > $(SOURCE_PATH)/src/quicly-tracer.h + +$(shell $(SOURCE_PATH)/../misc/probe2trace.pl -a particle < $(SOURCE_PATH)/../quicly-probes.d > $(SOURCE_PATH)/src/quicly-tracer.h) + +INCLUDE_DIRS+=\ + $(SOURCE_PATH)../deps/picotls/deps/cifra/src \ + $(SOURCE_PATH)/../deps/klib \ + $(SOURCE_PATH)/../deps/picotls/deps/cifra/src/ext \ + $(SOURCE_PATH)/../deps/picotls/deps/micro-ecc \ + $(SOURCE_PATH)/../deps/picotls/include \ + $(SOURCE_PATH)/../include \ + $(SOURCE_PATH)/src \ + +CSRC+=\ + ../deps/picotls/deps/cifra/src/aes.c \ + ../deps/picotls/deps/cifra/src/blockwise.c \ + ../deps/picotls/deps/cifra/src/chacha20.c \ + ../deps/picotls/deps/cifra/src/gcm.c \ + ../deps/picotls/deps/cifra/src/gf128.c \ + ../deps/picotls/deps/cifra/src/modes.c \ + ../deps/picotls/deps/cifra/src/poly1305.c \ + ../deps/picotls/deps/cifra/src/sha256.c \ + ../deps/picotls/deps/cifra/src/sha512.c \ + ../deps/picotls/deps/micro-ecc/uECC.c \ + ../deps/picotls/lib/cifra.c \ + ../deps/picotls/lib/cifra/aes128.c \ + ../deps/picotls/lib/cifra/aes256.c \ + ../deps/picotls/lib/cifra/chacha20.c \ + ../deps/picotls/lib/hpke.c \ + ../deps/picotls/lib/picotls.c \ + ../deps/picotls/lib/uecc.c \ + ../lib/cc-cubic.c \ + ../lib/cc-pico.c \ + ../lib/cc-reno.c \ + ../lib/defaults.c \ + ../lib/frame.c \ + ../lib/local_cid.c \ + ../lib/loss.c \ + ../lib/quicly.c \ + ../lib/ranges.c \ + ../lib/rate.c \ + ../lib/recvstate.c \ + ../lib/remote_cid.c \ + ../lib/retire_cid.c \ + ../lib/sendstate.c \ + ../lib/sentmap.c \ + ../lib/streambuf.c \ + +CSRC+=../src/cli.c +CPPSRC+=$(USRSRC)/main.cpp + +# -Wshadow +EXTRA_CFLAGS+=-Wno-undef -Wno-pointer-to-int-cast -Werror +EXTRA_CFLAGS+=-Wall -Wextra -Wdouble-promotion -Wformat=2 -Wformat-truncation -Wno-sign-compare -Wno-missing-field-initializers +EXTRA_CFLAGS+=-fstack-usage -Wstack-usage=200 -Wno-error=stack-usage= +EXTRA_CFLAGS+=-DPTLS_MINIMIZE_STACK +# EXTRA_CFLAGS+=-DNO_LOG -Wno-unused-but-set-variable +EXTRA_CFLAGS+=-DAVOID_64BIT +EXTRA_CFLAGS+=-DQUICLY_USE_TRACER +# EXTRA_CFLAGS+=-finstrument-functions -finstrument-functions-exclude-file-list=deps/micro-ecc,deps/cifra +# EXTRA_CFLAGS+=-DNDEBUG -Wno-unused-variable +EXTRA_CFLAGS+=-DQUICLY_CLIENT -DPICOTLS_CLIENT +EXTRA_CFLAGS+=-DFULL_FAT_ASSERT +# EXTRA_CFLAGS+=-DPTLS_DEBUG diff --git a/particle/src/main.cpp b/particle/src/main.cpp new file mode 100644 index 00000000..21a26384 --- /dev/null +++ b/particle/src/main.cpp @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: BSD-2-Clause +// +// Copyright (c) 2023, NetApp, Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#include "quic.h" + +#include + +SYSTEM_MODE(MANUAL); +// SYSTEM_THREAD(ENABLED); + +#if !defined(NDEBUG) +SerialLogHandler logHandler(LOG_LEVEL_TRACE); +#endif + +static const int led = D7; + +// don't use entropy from cloud +void random_seed_from_cloud(unsigned int seed) +{ +} + +static ApplicationWatchdog wd(60000, System.reset); + +extern "C" void ping(void) +{ + wd.checkin(); +} + +void button_action() +{ + digitalWrite(led, HIGH); + + LOG_PRINTF(INFO, "Particle Device OS: %lu.%lu.%lu\n", (System.versionNumber() & 0xff000000) >> 24, + (System.versionNumber() & 0x00ff0000) >> 16, (System.versionNumber() & 0x0000ff00) >> 8); + + quic_transaction("172.16.100.12", "4435", "/2000"); + + // WiFi.off(); + delay(1s); + digitalWrite(led, LOW); +} + +void setup() +{ + Serial.begin(9600); + delay(1000); + + WiFi.on(); + WiFi.connect(WIFI_CONNECT_SKIP_LISTEN); + waitUntil(WiFi.ready); + + // let's gather some weak entropy and seed the RNG + const int temp = analogRead(A0); + const int volt = analogRead(BATT); + randomSeed(((temp << 12) | volt)); + + pinMode(led, OUTPUT); + // button_action(); +} + +void loop() +{ + button_action(); + delay(1s); + // System.sleep(BTN, FALLING); + // if (System.sleepResult().reason() == WAKEUP_REASON_PIN) + // button_action(); +} + +static uint32_t stack_lim = 0; +static uint32_t max_stack = 0; +static uint32_t heap_lim = 0; +static uint32_t dstack_depth = 0; + +extern "C" void __attribute__((no_instrument_function)) __cyg_profile_func_enter(void *, void *) +{ + static const char *stack_start = 0; + dstack_depth++; + const char *const frame = (const char *)__builtin_frame_address(0); + if (stack_lim == 0) { + stack_start = frame; + + stack_lim = 6144; // TODO: can this be determined dynamically? + } + + uint32_t heap = 0; + runtime_info_t info = {.size = sizeof(info)}; + HAL_Core_Runtime_Info(&info, NULL); + heap = info.freeheap; + heap_lim = info.total_init_heap; + + const uint32_t stack = (uint32_t)(stack_start - frame); + + LOG_PRINTF(INFO, "s=%" PRIu32 " h=%" PRIu32 " l=%" PRIu32 "\n", stack, heap, dstack_depth); + + if (stack < UINT16_MAX) + max_stack = MAX(max_stack, stack); +} + +extern "C" void __attribute__((no_instrument_function)) __cyg_profile_func_exit(void *, void *) +{ + dstack_depth--; +} diff --git a/particle/src/quic.h b/particle/src/quic.h new file mode 100644 index 00000000..dd4017c4 --- /dev/null +++ b/particle/src/quic.h @@ -0,0 +1,11 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +extern int quic_transaction(const char *host, const char *port, const char *req); + +#ifdef __cplusplus +} +#endif diff --git a/src/cli.c b/src/cli.c index eed2cc78..a59f09a0 100644 --- a/src/cli.c +++ b/src/cli.c @@ -24,9 +24,11 @@ #include #include #include +#ifndef PARTICLE #include #include #include +#endif #include #include #include @@ -39,7 +41,22 @@ #include "quicly/streambuf.h" #include "../deps/picotls/t/util.h" +#if PARTICLE +#include +#include +#include + +#include + +#define perror(x) LOG_PRINTF(INFO, x "\n") +#define fprintf(x, ...) LOG_PRINTF(INFO, __VA_ARGS__) +#define fputs(x, y) LOG_PRINTF(INFO, x "\n") +#define fputc(x, y) LOG_PRINTF(INFO, "%c", x) + +#define MAX_BURST_PACKETS 2 // FIXME: assert fails w/1 +#else #define MAX_BURST_PACKETS 10 +#endif FILE *quicly_trace_fp = NULL; static unsigned verbosity = 0; @@ -76,7 +93,9 @@ static struct { } address_token_aead; static ptls_save_ticket_t save_session_ticket = {save_session_ticket_cb}; static ptls_on_client_hello_t on_client_hello = {on_client_hello_cb}; +#if defined(QUICLY_SERVER) || !defined(QUICLY_CLIENT) static int enforce_retry; +#endif #if QUICLY_HAVE_FUSION static const ptls_cipher_suite_t fusion_aes128gcmsha256 = {PTLS_CIPHER_SUITE_AES_128_GCM_SHA256, &ptls_fusion_aes128gcm, @@ -87,6 +106,44 @@ static const ptls_cipher_suite_t fusion_aes128gcmsha256 = {PTLS_CIPHER_SUITE_AES static ptls_key_exchange_algorithm_t *key_exchanges[128]; static ptls_cipher_suite_t *cipher_suites[128]; + +#ifdef PARTICLE + +static uint64_t get_time(ptls_get_time_t *self) +{ + return HAL_Timer_Get_Milli_Seconds(); +} + +static void random_bytes(void *buf, size_t len) +{ + // FIXME: HAL_RNG_GetRandomNumber can be slow - use a PRNG + while (len >= sizeof(uint32_t)) { + *((uint32_t *)buf) = HAL_RNG_GetRandomNumber(); + buf += sizeof(uint32_t); + len -= sizeof(uint32_t); + } + while (len > 0) { + *((uint8_t *)buf) = HAL_RNG_GetRandomNumber(); + buf += sizeof(uint8_t); + len -= sizeof(uint8_t); + } +} + +static int uecc_rng(uint8_t * dest, unsigned size) +{ + random_bytes(dest, size); + return 1; +} + +static ptls_context_t tlsctx = {.random_bytes = random_bytes, + .get_time = &(ptls_get_time_t){get_time}, + .key_exchanges = key_exchanges, + .cipher_suites = cipher_suites, + // .ech.client = {ptls_openssl_hpke_cipher_suites, ptls_openssl_hpke_kems}, + .require_dhe_on_psk = 1, + .save_ticket = &save_session_ticket, + .on_client_hello = &on_client_hello}; +#else static ptls_context_t tlsctx = {.random_bytes = ptls_openssl_random_bytes, .get_time = &ptls_get_time, .key_exchanges = key_exchanges, @@ -95,6 +152,7 @@ static ptls_context_t tlsctx = {.random_bytes = ptls_openssl_random_bytes, .require_dhe_on_psk = 1, .save_ticket = &save_session_ticket, .on_client_hello = &on_client_hello}; +#endif static struct { ptls_iovec_t list[16]; size_t count; @@ -115,25 +173,30 @@ struct st_stream_data_t { static void on_stop_sending(quicly_stream_t *stream, int err); static void on_receive_reset(quicly_stream_t *stream, int err); + +#if defined(QUICLY_SERVER) || !defined(QUICLY_CLIENT) static void server_on_receive(quicly_stream_t *stream, size_t off, const void *src, size_t len); +static const quicly_stream_callbacks_t server_stream_callbacks = { + quicly_streambuf_destroy, quicly_streambuf_egress_shift, quicly_streambuf_egress_emit, on_stop_sending, server_on_receive, + on_receive_reset}; +#endif +#if defined(QUICLY_CLIENT) || !defined(QUICLY_SERVER) static void client_on_receive(quicly_stream_t *stream, size_t off, const void *src, size_t len); - -static const quicly_stream_callbacks_t server_stream_callbacks = {quicly_streambuf_destroy, - quicly_streambuf_egress_shift, - quicly_streambuf_egress_emit, - on_stop_sending, - server_on_receive, - on_receive_reset}, - client_stream_callbacks = {quicly_streambuf_destroy, - quicly_streambuf_egress_shift, - quicly_streambuf_egress_emit, - on_stop_sending, - client_on_receive, - on_receive_reset}; +static const quicly_stream_callbacks_t client_stream_callbacks = { + quicly_streambuf_destroy, quicly_streambuf_egress_shift, quicly_streambuf_egress_emit, on_stop_sending, client_on_receive, + on_receive_reset}; +#endif static void dump_stats(FILE *fp, quicly_conn_t *conn) { +#ifdef PTLS_MINIMIZE_STACK + quicly_stats_t *tmp_stats __attribute__((__cleanup__(ptls_cleanup_free))) = malloc(sizeof(quicly_stats_t)); + if (tmp_stats == NULL) + return; +#define stats (*tmp_stats) +#else quicly_stats_t stats; +#endif quicly_get_stats(conn, &stats); fprintf(fp, @@ -143,6 +206,7 @@ static void dump_stats(FILE *fp, quicly_conn_t *conn) stats.num_packets.received, stats.num_packets.decryption_failed, stats.num_packets.sent, stats.num_packets.lost, stats.num_packets.ack_received, stats.num_packets.late_acked, stats.num_bytes.received, stats.num_bytes.sent, stats.rtt.smoothed); +#undef stats } static int validate_path(const char *path) @@ -155,6 +219,7 @@ static int validate_path(const char *path) return 1; } +#if defined(QUICLY_SERVER) || !defined(QUICLY_CLIENT) static int parse_request(ptls_iovec_t input, char **path, int *is_http1) { size_t off = 0, path_start; @@ -178,12 +243,14 @@ static int parse_request(ptls_iovec_t input, char **path, int *is_http1) input.base[off] = '\0'; return 1; } +#endif static void send_str(quicly_stream_t *stream, const char *s) { quicly_streambuf_egress_write(stream, s, strlen(s)); } +#if defined(QUICLY_SERVER) || !defined(QUICLY_CLIENT) static void send_header(quicly_stream_t *stream, int is_http1, int status, const char *mime_type) { char buf[256]; @@ -195,6 +262,7 @@ static void send_header(quicly_stream_t *stream, int is_http1, int status, const send_str(stream, buf); } +#ifndef PARTICLE static int flatten_file_vec(quicly_sendbuf_vec_t *vec, void *dst, size_t off, size_t len) { int fd = (intptr_t)vec->cbdata; @@ -212,9 +280,13 @@ static void discard_file_vec(quicly_sendbuf_vec_t *vec) int fd = (intptr_t)vec->cbdata; close(fd); } +#endif static int send_file(quicly_stream_t *stream, int is_http1, const char *fn, const char *mime_type) { +#ifdef PARTICLE + return 0; +#else static const quicly_streambuf_sendvec_callbacks_t send_file_callbacks = {flatten_file_vec, discard_file_vec}; int fd; struct stat st; @@ -230,6 +302,7 @@ static int send_file(quicly_stream_t *stream, int is_http1, const char *fn, cons quicly_sendbuf_vec_t vec = {&send_file_callbacks, (size_t)st.st_size, (void *)(intptr_t)fd}; quicly_streambuf_egress_write_vec(stream, &vec); return 1; +#endif } /** @@ -288,6 +361,7 @@ static int send_sized_text(quicly_stream_t *stream, const char *path, int is_htt quicly_streambuf_egress_write_vec(stream, &vec); return 1; } +#endif static void on_stop_sending(quicly_stream_t *stream, int err) { @@ -301,6 +375,7 @@ static void on_receive_reset(quicly_stream_t *stream, int err) fprintf(stderr, "received RESET_STREAM: %" PRIu16 "\n", QUICLY_ERROR_GET_ERROR_CODE(err)); } +#if defined(QUICLY_SERVER) || !defined(QUICLY_CLIENT) static void server_on_receive(quicly_stream_t *stream, size_t off, const void *src, size_t len) { char *path; @@ -338,6 +413,7 @@ static void server_on_receive(quicly_stream_t *stream, size_t off, const void *s quicly_streambuf_egress_shutdown(stream); quicly_streambuf_ingress_shift(stream, len); } +#endif static void client_on_receive(quicly_stream_t *stream, size_t off, const void *src, size_t len) { @@ -378,7 +454,15 @@ static int on_stream_open(quicly_stream_open_t *self, quicly_stream_t *stream) if ((ret = quicly_streambuf_create(stream, sizeof(struct st_stream_data_t))) != 0) return ret; +#if defined(QUICLY_CLIENT) && !defined(QUICLY_SERVER) + assert(ctx.tls->certificates.count == 0); + stream->callbacks = &client_stream_callbacks; +#elif !defined(QUICLY_CLIENT) && defined(QUICLY_SERVER) + assert(ctx.tls->certificates.count != 0); + stream->callbacks = &server_stream_callbacks; +#else stream->callbacks = ctx.tls->certificates.count != 0 ? &server_stream_callbacks : &client_stream_callbacks; +#endif return 0; } @@ -472,21 +556,30 @@ static void send_packets_gso(int fd, struct sockaddr *dest, struct iovec *packet static void (*send_packets)(int, struct sockaddr *, struct iovec *, size_t) = send_packets_default; +#if defined(QUICLY_SERVER) || !defined(QUICLY_CLIENT) static void send_one_packet(int fd, struct sockaddr *dest, const void *payload, size_t payload_len) { struct iovec vec = {.iov_base = (void *)payload, .iov_len = payload_len}; send_packets(fd, dest, &vec, 1); } +#endif static int send_pending(int fd, quicly_conn_t *conn) { quicly_address_t dest, src; struct iovec packets[MAX_BURST_PACKETS]; - uint8_t buf[MAX_BURST_PACKETS * quicly_get_context(conn)->transport_params.max_udp_payload_size]; + const size_t buf_size = MAX_BURST_PACKETS * quicly_get_context(conn)->transport_params.max_udp_payload_size; +#ifdef PTLS_MINIMIZE_STACK + uint8_t *buf __attribute__((__cleanup__(ptls_cleanup_free))) = malloc(buf_size); + if (buf == NULL) + return PTLS_ERROR_NO_MEMORY; +#else + uint8_t buf[buf_size]; +#endif size_t num_packets = MAX_BURST_PACKETS; int ret; - if ((ret = quicly_send(conn, &dest, &src, packets, &num_packets, buf, sizeof(buf))) == 0 && num_packets != 0) + if ((ret = quicly_send(conn, &dest, &src, packets, &num_packets, buf, buf_size)) == 0 && num_packets != 0) send_packets(fd, &dest.sa, packets, num_packets); return ret; @@ -504,9 +597,11 @@ static void enqueue_requests(quicly_conn_t *conn) { size_t i; int ret; + char *req = malloc(1024); + char *destfile = malloc(1024); + assert(req && destfile); for (i = 0; reqs[i].path != NULL; ++i) { - char req[1024], destfile[1024]; quicly_stream_t *stream; ret = quicly_open_stream(conn, &stream, 0); assert(ret == 0); @@ -527,6 +622,7 @@ static void enqueue_requests(quicly_conn_t *conn) enqueue_requests_at = INT64_MAX; } +#if defined(QUICLY_CLIENT) || !defined(QUICLY_SERVER) static int run_client(int fd, struct sockaddr *sa, const char *host) { struct sockaddr_in local; @@ -573,7 +669,12 @@ static int run_client(int fd, struct sockaddr *sa, const char *host) enqueue_requests(conn); if (FD_ISSET(fd, &readfds)) { while (1) { +#ifdef PTLS_MINIMIZE_STACK + uint8_t *buf __attribute__((__cleanup__(ptls_cleanup_free))) = malloc(ctx.transport_params.max_udp_payload_size); + assert(buf); +#else uint8_t buf[ctx.transport_params.max_udp_payload_size]; +#endif struct msghdr mess; struct sockaddr sa; struct iovec vec; @@ -581,7 +682,7 @@ static int run_client(int fd, struct sockaddr *sa, const char *host) mess.msg_name = &sa; mess.msg_namelen = sizeof(sa); vec.iov_base = buf; - vec.iov_len = sizeof(buf); + vec.iov_len = ctx.transport_params.max_udp_payload_size; mess.msg_iov = &vec; mess.msg_iovlen = 1; ssize_t rret; @@ -609,7 +710,9 @@ static int run_client(int fd, struct sockaddr *sa, const char *host) if (conn != NULL) { ret = send_pending(fd, conn); if (ret != 0) { +#ifndef PARTICLE ech_save_retry_configs(); +#endif quicly_free(conn); conn = NULL; if (ret == QUICLY_ERROR_FREE_CONNECTION) { @@ -622,10 +725,13 @@ static int run_client(int fd, struct sockaddr *sa, const char *host) } } } +#endif +#if defined(QUICLY_SERVER) || !defined(QUICLY_CLIENT) static quicly_conn_t **conns; static size_t num_conns = 0; +#ifndef PARTICLE static void on_signal(int signo) { size_t i; @@ -637,6 +743,7 @@ static void on_signal(int signo) if (signo == SIGINT) _exit(0); } +#endif static int validate_token(struct sockaddr *remote, ptls_iovec_t client_cid, ptls_iovec_t server_cid, quicly_address_token_plaintext_t *token, const char **err_desc) @@ -707,11 +814,15 @@ static int validate_token(struct sockaddr *remote, ptls_iovec_t client_cid, ptls *err_desc = "CID mismatch"; return 0; } +#endif +#if defined(QUICLY_SERVER) || !defined(QUICLY_CLIENT) static int run_server(int fd, struct sockaddr *sa, socklen_t salen) { +#ifndef PARTICLE signal(SIGINT, on_signal); signal(SIGHUP, on_signal); +#endif if (bind(fd, sa, salen) != 0) { perror("bind(2) failed"); @@ -873,7 +984,9 @@ static int run_server(int fd, struct sockaddr *sa, socklen_t salen) } } } +#endif +#ifndef PARTICLE static void load_session(void) { static uint8_t buf[65536]; @@ -916,6 +1029,7 @@ static void load_session(void) Exit:; } +#endif static struct { ptls_iovec_t tls_ticket; @@ -1002,6 +1116,7 @@ static int on_client_hello_cb(ptls_on_client_hello_t *_self, ptls_t *tls, ptls_o return 0; } +#ifndef PARTICLE static void usage(const char *cmd) { printf("Usage: %s [options] host port\n" @@ -1062,6 +1177,7 @@ static void usage(const char *cmd) "\n", cmd); } +#endif static void push_req(const char *path, int to_file) { @@ -1074,13 +1190,22 @@ static void push_req(const char *path, int to_file) memset(reqs + i + 1, 0, sizeof(*reqs)); } +#ifdef PARTICLE +int quic_transaction(const char *host, const char *port, const char *req) +#else int main(int argc, char **argv) +#endif { +#ifndef PARTICLE const char *cert_file = NULL, *raw_pubkey_file = NULL, *host, *port, *cid_key = NULL; +#endif struct sockaddr_storage sa; socklen_t salen; unsigned udpbufsize = 0; - int ch, opt_index, fd; +#ifndef PARTICLE + int ch, opt_index; +#endif + int fd; reqs = malloc(sizeof(*reqs)); memset(reqs, 0, sizeof(*reqs)); @@ -1101,6 +1226,7 @@ int main(int argc, char **argv) address_token_aead.dec = ptls_aead_new(&ptls_openssl_aes128gcm, &ptls_openssl_sha256, 0, secret, ""); } +#ifndef PARTICLE static const struct option longopts[] = { {"ech-key", required_argument, NULL, 0}, {"ech-configs", required_argument, NULL, 0}, {NULL}}; while ((ch = getopt_long(argc, argv, "a:b:B:c:C:Dd:k:Ee:f:Gi:I:K:l:M:m:NnOp:P:Rr:S:s:u:U:Vvw:W:x:X:y:h", longopts, @@ -1341,6 +1467,14 @@ int main(int argc, char **argv) } argc -= optind; argv += optind; +#else + // negotiated_protocols.list[negotiated_protocols.count++] = ptls_iovec_init("hq-interop", strlen("hq-interop")); + if (!validate_path(req)) { + fprintf(stderr, "invalid path:%s\n", req); + exit(1); + } + push_req(req, 0); +#endif if (reqs[0].path == NULL) push_req("/", 0); @@ -1380,6 +1514,7 @@ int main(int argc, char **argv) ctx.transport_params.max_datagram_frame_size = ctx.transport_params.max_udp_payload_size; } +#ifndef PARTICLE if (cert_file != NULL || ctx.tls->sign_certificate != NULL) { /* server */ if (cert_file == NULL || ctx.tls->sign_certificate == NULL) { @@ -1416,8 +1551,12 @@ int main(int argc, char **argv) EVP_PKEY_free(pubkey); ctx.tls->use_raw_public_keys = 1; } +#else + uECC_set_rng(uecc_rng); +#endif hs_properties.client.negotiated_protocols.list = negotiated_protocols.list; hs_properties.client.negotiated_protocols.count = negotiated_protocols.count; +#ifndef PARTICLE if (session_file != NULL) load_session(); hs_properties.client.ech.configs = ech.config_list; @@ -1429,6 +1568,7 @@ int main(int argc, char **argv) } host = (--argc, *argv++); port = (--argc, *argv++); +#endif if (resolve_address((void *)&sa, &salen, host, port, AF_INET, SOCK_DGRAM, IPPROTO_UDP) != 0) exit(1); @@ -1437,7 +1577,9 @@ int main(int argc, char **argv) perror("socket(2) failed"); return 1; } +#ifndef PARTICLE fcntl(fd, F_SETFL, O_NONBLOCK); +#endif { int on = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) != 0) { @@ -1471,5 +1613,13 @@ int main(int argc, char **argv) } #endif +#if defined(QUICLY_CLIENT) && !defined(QUICLY_SERVER) + assert(ctx.tls->certificates.count == 0); + return run_client(fd, (void *)&sa, host); +#elif defined(QUICLY_CLIENT) && !defined(QUICLY_SERVER) + assert(ctx.tls->certificates.count != 0); + return run_server(fd, (void *)&sa, salen); +#else return ctx.tls->certificates.count != 0 ? run_server(fd, (void *)&sa, salen) : run_client(fd, (void *)&sa, host); +#endif }