From be3e225a493d79c4c721290b7ef7bf081e30a652 Mon Sep 17 00:00:00 2001 From: Shichao Date: Sun, 19 May 2024 13:07:15 +0800 Subject: http3: handle read from sock. --- src/service/transport/gnunet-communicator-http3.c | 297 ++++++++++++++++++++++ 1 file changed, 297 insertions(+) diff --git a/src/service/transport/gnunet-communicator-http3.c b/src/service/transport/gnunet-communicator-http3.c index 806e5209d..428788fb8 100644 --- a/src/service/transport/gnunet-communicator-http3.c +++ b/src/service/transport/gnunet-communicator-http3.c @@ -17,6 +17,8 @@ #include #include #include +#include +#include /** @@ -39,6 +41,8 @@ /** * Map of sockaddr -> struct Connection + * + * TODO: Maybe it would be better to use cid as key? */ struct GNUNET_CONTAINER_MultiHashMap *addr_map; @@ -161,6 +165,16 @@ struct Connection * Flag to indicate if we are the initiator of the connection */ int is_initiator; + + /** + * Flag to indicate whether we know the PeerIdentity (target) yet + */ + int id_rcvd; + + /** + * Flag to indicate whether we have sent OUR PeerIdentity to this peer + */ + int id_sent; }; @@ -178,6 +192,44 @@ timestamp (void) } +/** + * Taken from: UDP communicator + * Converts @a address to the address string format used by this + * communicator in HELLOs. + * + * @param address the address to convert, must be AF_INET or AF_INET6. + * @param address_len number of bytes in @a address + * @return string representation of @a address + */ +static char * +sockaddr_to_udpaddr_string (const struct sockaddr *address, + socklen_t address_len) +{ + char *ret; + + switch (address->sa_family) + { + case AF_INET: + GNUNET_asprintf (&ret, + "%s-%s", + COMMUNICATOR_ADDRESS_PREFIX, + GNUNET_a2s (address, address_len)); + break; + + case AF_INET6: + GNUNET_asprintf (&ret, + "%s-%s", + COMMUNICATOR_ADDRESS_PREFIX, + GNUNET_a2s (address, address_len)); + break; + + default: + GNUNET_assert (0); + } + return ret; +} + + /** * Convert UDP bind specification to a `struct sockaddr *` * @@ -758,6 +810,8 @@ mq_init (void *cls, connection->address_len = remote_addrlen; connection->target = *peer_id; connection->is_initiator = GNUNET_YES; + connection->id_rcvd = GNUNET_YES; + connection->id_sent = GNUNET_NO; connection->nt = GNUNET_NT_scanner_get_type (is, remote_addr, remote_addrlen); @@ -865,6 +919,135 @@ do_shutdown (void *cls) } +/** + * Accept new connections. + * + * @param local_addr local socket address + * @param local_addrlen local socket address length + * @param remote_addr remote(peer's) socket address + * @param remote_addrlen remote socket address length + * + * @return the pointer of new connection on success, NULL if failed + */ +static struct Connection* +accept_connection (struct sockaddr *local_addr, + socklen_t local_addrlen, + struct sockaddr *remote_addr, + socklen_t remote_addrlen, + uint8_t *data, + size_t datalen) +{ + ngtcp2_pkt_hd header; + struct Connection *new_connection = NULL; + ngtcp2_transport_params params; + ngtcp2_cid scid; + ngtcp2_conn *conn = NULL; + ngtcp2_settings settings; + uint8_t cid_buf[NGTCP2_MAX_CIDLEN]; + ngtcp2_path path = { + {local_addr, local_addrlen}, + {remote_addr, remote_addrlen}, + NULL, + }; + ngtcp2_callbacks callbacks = { + // .client_initial + .recv_client_initial = ngtcp2_crypto_recv_client_initial_cb, + .recv_crypto_data = ngtcp2_crypto_recv_crypto_data_cb, + .encrypt = ngtcp2_crypto_encrypt_cb, + .decrypt = ngtcp2_crypto_decrypt_cb, + .hp_mask = ngtcp2_crypto_hp_mask_cb, + // .recv_retry = ngtcp2_crypto_recv_retry_cb, + .update_key = ngtcp2_crypto_update_key_cb, + .delete_crypto_aead_ctx = ngtcp2_crypto_delete_crypto_aead_ctx_cb, + .delete_crypto_cipher_ctx = ngtcp2_crypto_delete_crypto_cipher_ctx_cb, + .get_path_challenge_data = ngtcp2_crypto_get_path_challenge_data_cb, + .version_negotiation = ngtcp2_crypto_version_negotiation_cb, + + // .acked_stream_data_offset = acked_stream_data_offset_cb, + // .recv_stream_data = recv_stream_data_cb, + // .stream_open = stream_open_cb, + .rand = rand_cb, + .get_new_connection_id = get_new_connection_id_cb, + }; + int rv; + + rv = ngtcp2_accept (&header, data, datalen); + if (rv < 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "ngtcp2_accept: %s\n", ngtcp2_strerror (rv)); + return NULL; + } + new_connection = GNUNET_new (struct Connection); + memset (new_connection, 0, sizeof (new_connection)); + + gnutls_init (&new_connection->session, + GNUTLS_SERVER + | GNUTLS_ENABLE_EARLY_DATA + | GNUTLS_NO_END_OF_EARLY_DATA); + gnutls_priority_set_direct (new_connection->session, PRIORITY, NULL); + /* + * TODO: The cred here has not been initialized and + * there is no need to maintain a cred for each connection + */ + gnutls_credentials_set (new_connection->session, + GNUTLS_CRD_CERTIFICATE, new_connection->cred); + + ngtcp2_transport_params_default (¶ms); + params.initial_max_streams_uni = 3; + params.initial_max_streams_bidi = 3; + params.initial_max_stream_data_bidi_local = 128 * 1024; + params.initial_max_stream_data_bidi_remote = 128 * 1024; + params.initial_max_data = 1024 * 1024; + params.original_dcid_present = 1; + params.max_idle_timeout = 30 * NGTCP2_SECONDS; + memcpy (¶ms.original_dcid, &header.dcid, + sizeof (params.original_dcid)); + + ngtcp2_settings_default (&settings); + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG, + cid_buf, + sizeof (cid_buf)); + ngtcp2_cid_init (&scid, cid_buf, sizeof (cid_buf)); + + rv = ngtcp2_conn_server_new (&conn, + &header.scid, + &scid, + &path, + header.version, + &callbacks, + &settings, + ¶ms, + NULL, + new_connection); + if (rv < 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "ngtcp2_conn_server_new: %s\n", + ngtcp2_strerror (rv)); + return NULL; + } + + new_connection->conn = conn; + new_connection->address = GNUNET_memdup (remote_addr, remote_addrlen); + new_connection->address_len = remote_addrlen; + new_connection->is_initiator = GNUNET_NO; + new_connection->id_rcvd = GNUNET_NO; + new_connection->id_sent = GNUNET_NO; + ngtcp2_crypto_gnutls_configure_server_session (new_connection->session); + ngtcp2_conn_set_tls_native_handle (new_connection->conn, + new_connection->session); + gnutls_session_set_ptr (new_connection->session, + &new_connection->conn_ref); + + new_connection->conn_ref.get_conn = get_conn; + new_connection->conn_ref.user_data = new_connection; + new_connection->stream.id = -1; + + return new_connection; +} + + /** * Socket read task. * @@ -873,6 +1056,120 @@ do_shutdown (void *cls) static void sock_read (void *cls) { + (void) cls; + struct sockaddr_storage sa; + socklen_t salen = sizeof (sa); + ssize_t rcvd; + uint8_t buf[UINT16_MAX]; + ngtcp2_path path; + // ngtcp2_version_cid version_cid; + struct GNUNET_HashCode addr_key; + struct Connection *connection; + int rv; + char *bindto; + struct sockaddr *local_addr; + socklen_t local_addrlen; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + COMMUNICATOR_CONFIG_SECTION, + "BINDTO", + &bindto)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + COMMUNICATOR_CONFIG_SECTION, + "BINDTO"); + return; + } + local_addr = udp_address_to_sockaddr (bindto, &local_addrlen); + read_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, + udp_sock, + &sock_read, + NULL); + + while (1) + { + rcvd = GNUNET_NETWORK_socket_recvfrom (udp_sock, + buf, + sizeof(buf), + (struct sockaddr *) &sa, + &salen); + if (-1 == rcvd) + { + struct sockaddr *addr = (struct sockaddr*) &sa; + + if (EAGAIN == errno) + break; // We are done reading data + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to recv from %s family %d failed sock %p\n", + GNUNET_a2s ((struct sockaddr*) &sa, + sizeof (*addr)), + addr->sa_family, + udp_sock); + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "recv"); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Read %llu bytes\n", + (unsigned long long) rcvd); + if (0 == rcvd) + { + GNUNET_break_op (0); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Read 0 bytes from UDP socket\n"); + return; + } + + // rv = ngtcp2_pkt_decode_version_cid (&version_cid, buf, rcvd, + // NGTCP2_MAX_CIDLEN); + // if (rv < 0) + // { + // GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + // "ngtcp2_pkt_decode_version_cid: %s\n", ngtcp2_strerror (rv)); + // return; + // } + + char *addr_string = + sockaddr_to_udpaddr_string ((const struct sockaddr *) &sa, + salen); + GNUNET_CRYPTO_hash (addr_string, strlen (addr_string), + &addr_key); + GNUNET_free (addr_string); + connection = GNUNET_CONTAINER_multihashmap_get (addr_map, &addr_key); + + if (NULL == connection) + { + connection = accept_connection (local_addr, local_addrlen, + (struct sockaddr *) &sa, + salen, buf, rcvd); + if (NULL == connection) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "accept connection error!\n"); + return; + } + GNUNET_CONTAINER_multihashmap_put (addr_map, + &addr_key, + connection, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); + } + + memcpy (&path, ngtcp2_conn_get_path (connection->conn), sizeof (path)); + path.remote.addr = (struct sockaddr *) &sa; + path.remote.addrlen = salen; + + rv = ngtcp2_conn_read_pkt (connection->conn, &path, NULL, buf, rcvd, + timestamp ()); + if (rv < 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "ngtcp2_conn_read_pkt: %s", + ngtcp2_strerror (rv)); + return; + } + } + + GNUNET_free (local_addr); } -- cgit v1.2.3