diff options
author | Shichao <mrrr61@outlook.com> | 2024-05-19 13:07:15 +0800 |
---|---|---|
committer | Shichao <mrrr61@outlook.com> | 2024-05-19 13:07:15 +0800 |
commit | be3e225a493d79c4c721290b7ef7bf081e30a652 (patch) | |
tree | 4ac33f40cce876d021bf5a406c33b266178debab | |
parent | b384ef7534238a99ae9f04083d9ced602af7e55d (diff) | |
download | gnunet-dev/shichao/http3.tar.gz gnunet-dev/shichao/http3.zip |
http3: handle read from sock.dev/shichao/http3
-rw-r--r-- | src/service/transport/gnunet-communicator-http3.c | 297 |
1 files changed, 297 insertions, 0 deletions
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 @@ | |||
17 | #include <ngtcp2/ngtcp2_crypto.h> | 17 | #include <ngtcp2/ngtcp2_crypto.h> |
18 | #include <ngtcp2/ngtcp2_crypto_gnutls.h> | 18 | #include <ngtcp2/ngtcp2_crypto_gnutls.h> |
19 | #include <nghttp3/nghttp3.h> | 19 | #include <nghttp3/nghttp3.h> |
20 | #include <gnutls/crypto.h> | ||
21 | #include <gnutls/gnutls.h> | ||
20 | 22 | ||
21 | 23 | ||
22 | /** | 24 | /** |
@@ -39,6 +41,8 @@ | |||
39 | 41 | ||
40 | /** | 42 | /** |
41 | * Map of sockaddr -> struct Connection | 43 | * Map of sockaddr -> struct Connection |
44 | * | ||
45 | * TODO: Maybe it would be better to use cid as key? | ||
42 | */ | 46 | */ |
43 | struct GNUNET_CONTAINER_MultiHashMap *addr_map; | 47 | struct GNUNET_CONTAINER_MultiHashMap *addr_map; |
44 | 48 | ||
@@ -161,6 +165,16 @@ struct Connection | |||
161 | * Flag to indicate if we are the initiator of the connection | 165 | * Flag to indicate if we are the initiator of the connection |
162 | */ | 166 | */ |
163 | int is_initiator; | 167 | int is_initiator; |
168 | |||
169 | /** | ||
170 | * Flag to indicate whether we know the PeerIdentity (target) yet | ||
171 | */ | ||
172 | int id_rcvd; | ||
173 | |||
174 | /** | ||
175 | * Flag to indicate whether we have sent OUR PeerIdentity to this peer | ||
176 | */ | ||
177 | int id_sent; | ||
164 | }; | 178 | }; |
165 | 179 | ||
166 | 180 | ||
@@ -179,6 +193,44 @@ timestamp (void) | |||
179 | 193 | ||
180 | 194 | ||
181 | /** | 195 | /** |
196 | * Taken from: UDP communicator | ||
197 | * Converts @a address to the address string format used by this | ||
198 | * communicator in HELLOs. | ||
199 | * | ||
200 | * @param address the address to convert, must be AF_INET or AF_INET6. | ||
201 | * @param address_len number of bytes in @a address | ||
202 | * @return string representation of @a address | ||
203 | */ | ||
204 | static char * | ||
205 | sockaddr_to_udpaddr_string (const struct sockaddr *address, | ||
206 | socklen_t address_len) | ||
207 | { | ||
208 | char *ret; | ||
209 | |||
210 | switch (address->sa_family) | ||
211 | { | ||
212 | case AF_INET: | ||
213 | GNUNET_asprintf (&ret, | ||
214 | "%s-%s", | ||
215 | COMMUNICATOR_ADDRESS_PREFIX, | ||
216 | GNUNET_a2s (address, address_len)); | ||
217 | break; | ||
218 | |||
219 | case AF_INET6: | ||
220 | GNUNET_asprintf (&ret, | ||
221 | "%s-%s", | ||
222 | COMMUNICATOR_ADDRESS_PREFIX, | ||
223 | GNUNET_a2s (address, address_len)); | ||
224 | break; | ||
225 | |||
226 | default: | ||
227 | GNUNET_assert (0); | ||
228 | } | ||
229 | return ret; | ||
230 | } | ||
231 | |||
232 | |||
233 | /** | ||
182 | * Convert UDP bind specification to a `struct sockaddr *` | 234 | * Convert UDP bind specification to a `struct sockaddr *` |
183 | * | 235 | * |
184 | * @param bindto bind specification to convert | 236 | * @param bindto bind specification to convert |
@@ -758,6 +810,8 @@ mq_init (void *cls, | |||
758 | connection->address_len = remote_addrlen; | 810 | connection->address_len = remote_addrlen; |
759 | connection->target = *peer_id; | 811 | connection->target = *peer_id; |
760 | connection->is_initiator = GNUNET_YES; | 812 | connection->is_initiator = GNUNET_YES; |
813 | connection->id_rcvd = GNUNET_YES; | ||
814 | connection->id_sent = GNUNET_NO; | ||
761 | connection->nt = GNUNET_NT_scanner_get_type (is, | 815 | connection->nt = GNUNET_NT_scanner_get_type (is, |
762 | remote_addr, | 816 | remote_addr, |
763 | remote_addrlen); | 817 | remote_addrlen); |
@@ -866,6 +920,135 @@ do_shutdown (void *cls) | |||
866 | 920 | ||
867 | 921 | ||
868 | /** | 922 | /** |
923 | * Accept new connections. | ||
924 | * | ||
925 | * @param local_addr local socket address | ||
926 | * @param local_addrlen local socket address length | ||
927 | * @param remote_addr remote(peer's) socket address | ||
928 | * @param remote_addrlen remote socket address length | ||
929 | * | ||
930 | * @return the pointer of new connection on success, NULL if failed | ||
931 | */ | ||
932 | static struct Connection* | ||
933 | accept_connection (struct sockaddr *local_addr, | ||
934 | socklen_t local_addrlen, | ||
935 | struct sockaddr *remote_addr, | ||
936 | socklen_t remote_addrlen, | ||
937 | uint8_t *data, | ||
938 | size_t datalen) | ||
939 | { | ||
940 | ngtcp2_pkt_hd header; | ||
941 | struct Connection *new_connection = NULL; | ||
942 | ngtcp2_transport_params params; | ||
943 | ngtcp2_cid scid; | ||
944 | ngtcp2_conn *conn = NULL; | ||
945 | ngtcp2_settings settings; | ||
946 | uint8_t cid_buf[NGTCP2_MAX_CIDLEN]; | ||
947 | ngtcp2_path path = { | ||
948 | {local_addr, local_addrlen}, | ||
949 | {remote_addr, remote_addrlen}, | ||
950 | NULL, | ||
951 | }; | ||
952 | ngtcp2_callbacks callbacks = { | ||
953 | // .client_initial | ||
954 | .recv_client_initial = ngtcp2_crypto_recv_client_initial_cb, | ||
955 | .recv_crypto_data = ngtcp2_crypto_recv_crypto_data_cb, | ||
956 | .encrypt = ngtcp2_crypto_encrypt_cb, | ||
957 | .decrypt = ngtcp2_crypto_decrypt_cb, | ||
958 | .hp_mask = ngtcp2_crypto_hp_mask_cb, | ||
959 | // .recv_retry = ngtcp2_crypto_recv_retry_cb, | ||
960 | .update_key = ngtcp2_crypto_update_key_cb, | ||
961 | .delete_crypto_aead_ctx = ngtcp2_crypto_delete_crypto_aead_ctx_cb, | ||
962 | .delete_crypto_cipher_ctx = ngtcp2_crypto_delete_crypto_cipher_ctx_cb, | ||
963 | .get_path_challenge_data = ngtcp2_crypto_get_path_challenge_data_cb, | ||
964 | .version_negotiation = ngtcp2_crypto_version_negotiation_cb, | ||
965 | |||
966 | // .acked_stream_data_offset = acked_stream_data_offset_cb, | ||
967 | // .recv_stream_data = recv_stream_data_cb, | ||
968 | // .stream_open = stream_open_cb, | ||
969 | .rand = rand_cb, | ||
970 | .get_new_connection_id = get_new_connection_id_cb, | ||
971 | }; | ||
972 | int rv; | ||
973 | |||
974 | rv = ngtcp2_accept (&header, data, datalen); | ||
975 | if (rv < 0) | ||
976 | { | ||
977 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
978 | "ngtcp2_accept: %s\n", ngtcp2_strerror (rv)); | ||
979 | return NULL; | ||
980 | } | ||
981 | new_connection = GNUNET_new (struct Connection); | ||
982 | memset (new_connection, 0, sizeof (new_connection)); | ||
983 | |||
984 | gnutls_init (&new_connection->session, | ||
985 | GNUTLS_SERVER | ||
986 | | GNUTLS_ENABLE_EARLY_DATA | ||
987 | | GNUTLS_NO_END_OF_EARLY_DATA); | ||
988 | gnutls_priority_set_direct (new_connection->session, PRIORITY, NULL); | ||
989 | /* | ||
990 | * TODO: The cred here has not been initialized and | ||
991 | * there is no need to maintain a cred for each connection | ||
992 | */ | ||
993 | gnutls_credentials_set (new_connection->session, | ||
994 | GNUTLS_CRD_CERTIFICATE, new_connection->cred); | ||
995 | |||
996 | ngtcp2_transport_params_default (¶ms); | ||
997 | params.initial_max_streams_uni = 3; | ||
998 | params.initial_max_streams_bidi = 3; | ||
999 | params.initial_max_stream_data_bidi_local = 128 * 1024; | ||
1000 | params.initial_max_stream_data_bidi_remote = 128 * 1024; | ||
1001 | params.initial_max_data = 1024 * 1024; | ||
1002 | params.original_dcid_present = 1; | ||
1003 | params.max_idle_timeout = 30 * NGTCP2_SECONDS; | ||
1004 | memcpy (¶ms.original_dcid, &header.dcid, | ||
1005 | sizeof (params.original_dcid)); | ||
1006 | |||
1007 | ngtcp2_settings_default (&settings); | ||
1008 | GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG, | ||
1009 | cid_buf, | ||
1010 | sizeof (cid_buf)); | ||
1011 | ngtcp2_cid_init (&scid, cid_buf, sizeof (cid_buf)); | ||
1012 | |||
1013 | rv = ngtcp2_conn_server_new (&conn, | ||
1014 | &header.scid, | ||
1015 | &scid, | ||
1016 | &path, | ||
1017 | header.version, | ||
1018 | &callbacks, | ||
1019 | &settings, | ||
1020 | ¶ms, | ||
1021 | NULL, | ||
1022 | new_connection); | ||
1023 | if (rv < 0) | ||
1024 | { | ||
1025 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1026 | "ngtcp2_conn_server_new: %s\n", | ||
1027 | ngtcp2_strerror (rv)); | ||
1028 | return NULL; | ||
1029 | } | ||
1030 | |||
1031 | new_connection->conn = conn; | ||
1032 | new_connection->address = GNUNET_memdup (remote_addr, remote_addrlen); | ||
1033 | new_connection->address_len = remote_addrlen; | ||
1034 | new_connection->is_initiator = GNUNET_NO; | ||
1035 | new_connection->id_rcvd = GNUNET_NO; | ||
1036 | new_connection->id_sent = GNUNET_NO; | ||
1037 | ngtcp2_crypto_gnutls_configure_server_session (new_connection->session); | ||
1038 | ngtcp2_conn_set_tls_native_handle (new_connection->conn, | ||
1039 | new_connection->session); | ||
1040 | gnutls_session_set_ptr (new_connection->session, | ||
1041 | &new_connection->conn_ref); | ||
1042 | |||
1043 | new_connection->conn_ref.get_conn = get_conn; | ||
1044 | new_connection->conn_ref.user_data = new_connection; | ||
1045 | new_connection->stream.id = -1; | ||
1046 | |||
1047 | return new_connection; | ||
1048 | } | ||
1049 | |||
1050 | |||
1051 | /** | ||
869 | * Socket read task. | 1052 | * Socket read task. |
870 | * | 1053 | * |
871 | * @param cls NULL | 1054 | * @param cls NULL |
@@ -873,6 +1056,120 @@ do_shutdown (void *cls) | |||
873 | static void | 1056 | static void |
874 | sock_read (void *cls) | 1057 | sock_read (void *cls) |
875 | { | 1058 | { |
1059 | (void) cls; | ||
1060 | struct sockaddr_storage sa; | ||
1061 | socklen_t salen = sizeof (sa); | ||
1062 | ssize_t rcvd; | ||
1063 | uint8_t buf[UINT16_MAX]; | ||
1064 | ngtcp2_path path; | ||
1065 | // ngtcp2_version_cid version_cid; | ||
1066 | struct GNUNET_HashCode addr_key; | ||
1067 | struct Connection *connection; | ||
1068 | int rv; | ||
1069 | char *bindto; | ||
1070 | struct sockaddr *local_addr; | ||
1071 | socklen_t local_addrlen; | ||
1072 | |||
1073 | if (GNUNET_OK != | ||
1074 | GNUNET_CONFIGURATION_get_value_string (cfg, | ||
1075 | COMMUNICATOR_CONFIG_SECTION, | ||
1076 | "BINDTO", | ||
1077 | &bindto)) | ||
1078 | { | ||
1079 | GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, | ||
1080 | COMMUNICATOR_CONFIG_SECTION, | ||
1081 | "BINDTO"); | ||
1082 | return; | ||
1083 | } | ||
1084 | local_addr = udp_address_to_sockaddr (bindto, &local_addrlen); | ||
1085 | read_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
1086 | udp_sock, | ||
1087 | &sock_read, | ||
1088 | NULL); | ||
1089 | |||
1090 | while (1) | ||
1091 | { | ||
1092 | rcvd = GNUNET_NETWORK_socket_recvfrom (udp_sock, | ||
1093 | buf, | ||
1094 | sizeof(buf), | ||
1095 | (struct sockaddr *) &sa, | ||
1096 | &salen); | ||
1097 | if (-1 == rcvd) | ||
1098 | { | ||
1099 | struct sockaddr *addr = (struct sockaddr*) &sa; | ||
1100 | |||
1101 | if (EAGAIN == errno) | ||
1102 | break; // We are done reading data | ||
1103 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1104 | "Failed to recv from %s family %d failed sock %p\n", | ||
1105 | GNUNET_a2s ((struct sockaddr*) &sa, | ||
1106 | sizeof (*addr)), | ||
1107 | addr->sa_family, | ||
1108 | udp_sock); | ||
1109 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "recv"); | ||
1110 | return; | ||
1111 | } | ||
1112 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1113 | "Read %llu bytes\n", | ||
1114 | (unsigned long long) rcvd); | ||
1115 | if (0 == rcvd) | ||
1116 | { | ||
1117 | GNUNET_break_op (0); | ||
1118 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1119 | "Read 0 bytes from UDP socket\n"); | ||
1120 | return; | ||
1121 | } | ||
1122 | |||
1123 | // rv = ngtcp2_pkt_decode_version_cid (&version_cid, buf, rcvd, | ||
1124 | // NGTCP2_MAX_CIDLEN); | ||
1125 | // if (rv < 0) | ||
1126 | // { | ||
1127 | // GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1128 | // "ngtcp2_pkt_decode_version_cid: %s\n", ngtcp2_strerror (rv)); | ||
1129 | // return; | ||
1130 | // } | ||
1131 | |||
1132 | char *addr_string = | ||
1133 | sockaddr_to_udpaddr_string ((const struct sockaddr *) &sa, | ||
1134 | salen); | ||
1135 | GNUNET_CRYPTO_hash (addr_string, strlen (addr_string), | ||
1136 | &addr_key); | ||
1137 | GNUNET_free (addr_string); | ||
1138 | connection = GNUNET_CONTAINER_multihashmap_get (addr_map, &addr_key); | ||
1139 | |||
1140 | if (NULL == connection) | ||
1141 | { | ||
1142 | connection = accept_connection (local_addr, local_addrlen, | ||
1143 | (struct sockaddr *) &sa, | ||
1144 | salen, buf, rcvd); | ||
1145 | if (NULL == connection) | ||
1146 | { | ||
1147 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1148 | "accept connection error!\n"); | ||
1149 | return; | ||
1150 | } | ||
1151 | GNUNET_CONTAINER_multihashmap_put (addr_map, | ||
1152 | &addr_key, | ||
1153 | connection, | ||
1154 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); | ||
1155 | } | ||
1156 | |||
1157 | memcpy (&path, ngtcp2_conn_get_path (connection->conn), sizeof (path)); | ||
1158 | path.remote.addr = (struct sockaddr *) &sa; | ||
1159 | path.remote.addrlen = salen; | ||
1160 | |||
1161 | rv = ngtcp2_conn_read_pkt (connection->conn, &path, NULL, buf, rcvd, | ||
1162 | timestamp ()); | ||
1163 | if (rv < 0) | ||
1164 | { | ||
1165 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1166 | "ngtcp2_conn_read_pkt: %s", | ||
1167 | ngtcp2_strerror (rv)); | ||
1168 | return; | ||
1169 | } | ||
1170 | } | ||
1171 | |||
1172 | GNUNET_free (local_addr); | ||
876 | 1173 | ||
877 | } | 1174 | } |
878 | 1175 | ||