diff options
author | marshall <stmr@umich.edu> | 2023-07-26 21:39:21 -0400 |
---|---|---|
committer | marshall <stmr@umich.edu> | 2023-07-26 21:43:16 -0400 |
commit | ba23b260c2d3f9fb49fa438e69396c2f6284f97d (patch) | |
tree | 4fcd6ffd8f2daef5a95ce8ac3db3d03e7bf07665 | |
parent | c84e4e6467937abbd78e5aedd915597978915a49 (diff) | |
download | gnunet-ba23b260c2d3f9fb49fa438e69396c2f6284f97d.tar.gz gnunet-ba23b260c2d3f9fb49fa438e69396c2f6284f97d.zip |
quic: optimize sock_read recv
-rw-r--r-- | src/transport/gnunet-communicator-quic.c | 346 |
1 files changed, 179 insertions, 167 deletions
diff --git a/src/transport/gnunet-communicator-quic.c b/src/transport/gnunet-communicator-quic.c index d95d3dd57..0d47f1469 100644 --- a/src/transport/gnunet-communicator-quic.c +++ b/src/transport/gnunet-communicator-quic.c | |||
@@ -1055,9 +1055,6 @@ mq_init (void *cls, const struct GNUNET_PeerIdentity *peer_id, const | |||
1055 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); | 1055 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); |
1056 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Added new peer to the addr map\n"); | 1056 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Added new peer to the addr map\n"); |
1057 | setup_peer_mq (peer); | 1057 | setup_peer_mq (peer); |
1058 | /** | ||
1059 | * TODO: destroy peers in hashmap | ||
1060 | */ | ||
1061 | if (NULL == timeout_task) | 1058 | if (NULL == timeout_task) |
1062 | timeout_task = GNUNET_SCHEDULER_add_now (&check_timeouts, NULL); | 1059 | timeout_task = GNUNET_SCHEDULER_add_now (&check_timeouts, NULL); |
1063 | GNUNET_free (local_addr); | 1060 | GNUNET_free (local_addr); |
@@ -1124,7 +1121,6 @@ sock_read (void *cls) | |||
1124 | uint8_t buf[UINT16_MAX]; | 1121 | uint8_t buf[UINT16_MAX]; |
1125 | uint8_t out[MAX_DATAGRAM_SIZE]; | 1122 | uint8_t out[MAX_DATAGRAM_SIZE]; |
1126 | ssize_t rcvd; | 1123 | ssize_t rcvd; |
1127 | (void) cls; | ||
1128 | 1124 | ||
1129 | ssize_t process_pkt; | 1125 | ssize_t process_pkt; |
1130 | struct QUIC_header quic_header; | 1126 | struct QUIC_header quic_header; |
@@ -1133,6 +1129,7 @@ sock_read (void *cls) | |||
1133 | struct PeerAddress *peer; | 1129 | struct PeerAddress *peer; |
1134 | struct GNUNET_HashCode addr_key; | 1130 | struct GNUNET_HashCode addr_key; |
1135 | 1131 | ||
1132 | (void) cls; | ||
1136 | quic_header.scid_len = sizeof(quic_header.scid); | 1133 | quic_header.scid_len = sizeof(quic_header.scid); |
1137 | quic_header.dcid_len = sizeof(quic_header.dcid); | 1134 | quic_header.dcid_len = sizeof(quic_header.dcid); |
1138 | quic_header.odcid_len = sizeof(quic_header.odcid); | 1135 | quic_header.odcid_len = sizeof(quic_header.odcid); |
@@ -1159,205 +1156,220 @@ sock_read (void *cls) | |||
1159 | udp_sock, | 1156 | udp_sock, |
1160 | &sock_read, | 1157 | &sock_read, |
1161 | NULL); | 1158 | NULL); |
1162 | rcvd = GNUNET_NETWORK_socket_recvfrom (udp_sock, | 1159 | while (1) |
1163 | buf, | 1160 | { |
1164 | sizeof(buf), | 1161 | rcvd = GNUNET_NETWORK_socket_recvfrom (udp_sock, |
1165 | (struct sockaddr *) &sa, | 1162 | buf, |
1166 | &salen); | 1163 | sizeof(buf), |
1164 | (struct sockaddr *) &sa, | ||
1165 | &salen); | ||
1166 | if (-1 == rcvd) | ||
1167 | { | ||
1168 | if (EAGAIN == errno) | ||
1169 | break; // We are done reading data | ||
1170 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "recv"); | ||
1171 | return; | ||
1172 | } | ||
1167 | 1173 | ||
1168 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 1174 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
1169 | "Read %lu bytes\n", rcvd); | 1175 | "Read %lu bytes\n", rcvd); |
1170 | 1176 | ||
1171 | if (-1 == rcvd) | 1177 | if (-1 == rcvd) |
1172 | { | 1178 | { |
1173 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "recv"); | 1179 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "recv"); |
1174 | return; | 1180 | return; |
1175 | } | 1181 | } |
1176 | GNUNET_CRYPTO_hash ((struct sockaddr *) &sa, salen, | 1182 | GNUNET_CRYPTO_hash ((struct sockaddr *) &sa, salen, |
1177 | &addr_key); | 1183 | &addr_key); |
1178 | peer = GNUNET_CONTAINER_multihashmap_get (addr_map, &addr_key); | 1184 | peer = GNUNET_CONTAINER_multihashmap_get (addr_map, &addr_key); |
1185 | |||
1186 | if (NULL == peer) | ||
1187 | { | ||
1188 | /** | ||
1189 | * Create new PeerAddress (receiver) with id_rcvd = false | ||
1190 | */ | ||
1191 | peer = GNUNET_new (struct PeerAddress); | ||
1192 | peer->address = GNUNET_memdup (&sa, salen); | ||
1193 | peer->address_len = salen; | ||
1194 | peer->id_rcvd = GNUNET_NO; | ||
1195 | peer->conn = NULL; | ||
1196 | peer->foreign_addr = sockaddr_to_udpaddr_string (peer->address, | ||
1197 | peer->address_len); | ||
1198 | setup_peer_mq (peer); | ||
1199 | if (GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_put (addr_map, | ||
1200 | &addr_key, | ||
1201 | peer, | ||
1202 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) | ||
1203 | { | ||
1204 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1205 | "tried to add duplicate address into address map\n"); | ||
1206 | return; | ||
1207 | } | ||
1208 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "added new peer to address map\n"); | ||
1209 | } | ||
1179 | 1210 | ||
1180 | if (NULL == peer) | ||
1181 | { | ||
1182 | /** | 1211 | /** |
1183 | * Create new PeerAddress (receiver) with id_rcvd = false | 1212 | * Parse QUIC info |
1184 | */ | 1213 | */ |
1185 | peer = GNUNET_new (struct PeerAddress); | 1214 | int rc = quiche_header_info (buf, rcvd, LOCAL_CONN_ID_LEN, |
1186 | peer->address = GNUNET_memdup (&sa, salen); | 1215 | &quic_header.version, |
1187 | peer->address_len = salen; | 1216 | &quic_header.type, quic_header.scid, |
1188 | peer->id_rcvd = GNUNET_NO; | 1217 | &quic_header.scid_len, quic_header.dcid, |
1189 | peer->conn = NULL; | 1218 | &quic_header.dcid_len, |
1190 | peer->foreign_addr = sockaddr_to_udpaddr_string (peer->address, | 1219 | quic_header.token, &quic_header.token_len); |
1191 | peer->address_len); | 1220 | if (0 > rc) |
1192 | if (GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_put (addr_map, &addr_key, | ||
1193 | peer, | ||
1194 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) | ||
1195 | { | 1221 | { |
1196 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 1222 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
1197 | "tried to add duplicate address into address map\n"); | 1223 | "failed to parse quic header: %d\n", |
1224 | rc); | ||
1198 | return; | 1225 | return; |
1199 | } | 1226 | } |
1200 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "added new peer to address map\n"); | ||
1201 | } | ||
1202 | 1227 | ||
1203 | /** | 1228 | /** |
1204 | * Parse QUIC info | 1229 | * New QUIC connection with peer |
1205 | */ | 1230 | */ |
1206 | int rc = quiche_header_info (buf, rcvd, LOCAL_CONN_ID_LEN, | 1231 | if (NULL == peer->conn) |
1207 | &quic_header.version, | ||
1208 | &quic_header.type, quic_header.scid, | ||
1209 | &quic_header.scid_len, quic_header.dcid, | ||
1210 | &quic_header.dcid_len, | ||
1211 | quic_header.token, &quic_header.token_len); | ||
1212 | if (0 > rc) | ||
1213 | { | ||
1214 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1215 | "failed to parse quic header: %d\n", | ||
1216 | rc); | ||
1217 | return; | ||
1218 | } | ||
1219 | |||
1220 | /** | ||
1221 | * New QUIC connection with peer | ||
1222 | */ | ||
1223 | if (NULL == peer->conn) | ||
1224 | { | ||
1225 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1226 | "attempting to create new connection\n"); | ||
1227 | if (0 == quiche_version_is_supported (quic_header.version)) | ||
1228 | { | 1232 | { |
1229 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 1233 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
1230 | "quic version negotiation initiated\n"); | 1234 | "attempting to create new connection\n"); |
1231 | /** | 1235 | if (0 == quiche_version_is_supported (quic_header.version)) |
1232 | * Write a version negotiation packet to "out" | ||
1233 | */ | ||
1234 | ssize_t written = quiche_negotiate_version (quic_header.scid, | ||
1235 | quic_header.scid_len, | ||
1236 | quic_header.dcid, | ||
1237 | quic_header.dcid_len, | ||
1238 | out, sizeof(out)); | ||
1239 | if (0 > written) | ||
1240 | { | 1236 | { |
1241 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 1237 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
1242 | "quiche failed to generate version negotiation packet\n"); | 1238 | "quic version negotiation initiated\n"); |
1239 | /** | ||
1240 | * Write a version negotiation packet to "out" | ||
1241 | */ | ||
1242 | ssize_t written = quiche_negotiate_version (quic_header.scid, | ||
1243 | quic_header.scid_len, | ||
1244 | quic_header.dcid, | ||
1245 | quic_header.dcid_len, | ||
1246 | out, sizeof(out)); | ||
1247 | if (0 > written) | ||
1248 | { | ||
1249 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1250 | "quiche failed to generate version negotiation packet\n"); | ||
1251 | return; | ||
1252 | } | ||
1253 | ssize_t sent = GNUNET_NETWORK_socket_sendto (udp_sock, | ||
1254 | out, | ||
1255 | written, | ||
1256 | (struct sockaddr*) &sa, | ||
1257 | salen); | ||
1258 | if (sent != written) | ||
1259 | { | ||
1260 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1261 | "failed to send version negotiation packet to peer\n"); | ||
1262 | return; | ||
1263 | } | ||
1264 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1265 | "sent %zd bytes to peer during version negotiation\n", | ||
1266 | sent); | ||
1243 | return; | 1267 | return; |
1244 | } | 1268 | } |
1245 | ssize_t sent = GNUNET_NETWORK_socket_sendto (udp_sock, | 1269 | |
1246 | out, | 1270 | if (0 == quic_header.token_len) |
1247 | written, | ||
1248 | (struct sockaddr*) &sa, | ||
1249 | salen); | ||
1250 | if (sent != written) | ||
1251 | { | 1271 | { |
1252 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 1272 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "quic stateless retry\n"); |
1253 | "failed to send version negotiation packet to peer\n"); | 1273 | mint_token (quic_header.dcid, quic_header.dcid_len, &sa, salen, |
1254 | return; | 1274 | quic_header.token, &quic_header.token_len); |
1275 | |||
1276 | uint8_t new_cid[LOCAL_CONN_ID_LEN]; | ||
1277 | GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG, new_cid, | ||
1278 | LOCAL_CONN_ID_LEN); | ||
1279 | |||
1280 | ssize_t written = quiche_retry (quic_header.scid, quic_header.scid_len, | ||
1281 | quic_header.dcid, quic_header.dcid_len, | ||
1282 | new_cid, LOCAL_CONN_ID_LEN, | ||
1283 | quic_header.token, | ||
1284 | quic_header.token_len, | ||
1285 | quic_header.version, out, sizeof(out)); | ||
1286 | if (0 > written) | ||
1287 | { | ||
1288 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1289 | "quiche failed to write retry packet\n"); | ||
1290 | return; | ||
1291 | } | ||
1292 | ssize_t sent = GNUNET_NETWORK_socket_sendto (udp_sock, | ||
1293 | out, | ||
1294 | written, | ||
1295 | (struct sockaddr*) &sa, | ||
1296 | salen); | ||
1297 | if (written != sent) | ||
1298 | { | ||
1299 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "failed to send retry packet\n"); | ||
1300 | return; | ||
1301 | } | ||
1302 | |||
1303 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sent %zd bytes\n", sent); | ||
1255 | } | 1304 | } |
1256 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1257 | "sent %zd bytes to peer during version negotiation\n", sent); | ||
1258 | return; | ||
1259 | } | ||
1260 | 1305 | ||
1261 | if (0 == quic_header.token_len) | 1306 | if (GNUNET_OK != validate_token (quic_header.token, quic_header.token_len, |
1262 | { | 1307 | &sa, salen, |
1263 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "quic stateless retry\n"); | 1308 | quic_header.odcid, |
1264 | mint_token (quic_header.dcid, quic_header.dcid_len, &sa, salen, | 1309 | &quic_header.odcid_len)) |
1265 | quic_header.token, &quic_header.token_len); | ||
1266 | |||
1267 | uint8_t new_cid[LOCAL_CONN_ID_LEN]; | ||
1268 | GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG, new_cid, | ||
1269 | LOCAL_CONN_ID_LEN); | ||
1270 | |||
1271 | ssize_t written = quiche_retry (quic_header.scid, quic_header.scid_len, | ||
1272 | quic_header.dcid, quic_header.dcid_len, | ||
1273 | new_cid, LOCAL_CONN_ID_LEN, | ||
1274 | quic_header.token, quic_header.token_len, | ||
1275 | quic_header.version, out, sizeof(out)); | ||
1276 | if (0 > written) | ||
1277 | { | 1310 | { |
1278 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 1311 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
1279 | "quiche failed to write retry packet\n"); | 1312 | "invalid address validation token created\n"); |
1280 | return; | 1313 | return; |
1281 | } | 1314 | } |
1282 | ssize_t sent = GNUNET_NETWORK_socket_sendto (udp_sock, | 1315 | peer->conn = create_conn (quic_header.dcid, quic_header.dcid_len, |
1283 | out, | 1316 | quic_header.odcid, quic_header.odcid_len, |
1284 | written, | 1317 | local_addr, in_len, |
1285 | (struct sockaddr*) &sa, | 1318 | &sa, salen); |
1286 | salen); | 1319 | if (NULL == peer->conn) |
1287 | if (written != sent) | ||
1288 | { | 1320 | { |
1289 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "failed to send retry packet\n"); | 1321 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
1322 | "failed to create quic connection with peer\n"); | ||
1290 | return; | 1323 | return; |
1291 | } | 1324 | } |
1325 | } // null connection | ||
1292 | 1326 | ||
1293 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sent %zd bytes\n", sent); | 1327 | quiche_recv_info recv_info = { |
1294 | } | 1328 | (struct sockaddr *) &sa, |
1329 | salen, | ||
1295 | 1330 | ||
1296 | if (GNUNET_OK != validate_token (quic_header.token, quic_header.token_len, | 1331 | local_addr, |
1297 | &sa, salen, | 1332 | in_len, |
1298 | quic_header.odcid, &quic_header.odcid_len)) | 1333 | }; |
1334 | process_pkt = quiche_conn_recv (peer->conn->conn, buf, rcvd, &recv_info); | ||
1335 | if (0 > process_pkt) | ||
1299 | { | 1336 | { |
1300 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 1337 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
1301 | "invalid address validation token created\n"); | 1338 | "quiche failed to process received packet: %zd\n", |
1339 | process_pkt); | ||
1302 | return; | 1340 | return; |
1303 | } | 1341 | } |
1304 | peer->conn = create_conn (quic_header.dcid, quic_header.dcid_len, | 1342 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
1305 | quic_header.odcid, quic_header.odcid_len, | 1343 | "quiche processed %zd bytes\n", process_pkt); |
1306 | local_addr, in_len, | 1344 | /** |
1307 | &sa, salen); | 1345 | * Check for connection establishment |
1308 | if (NULL == peer->conn) | 1346 | */ |
1347 | if (quiche_conn_is_established (peer->conn->conn)) | ||
1309 | { | 1348 | { |
1310 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 1349 | // Check for data on all available streams |
1311 | "failed to create quic connection with peer\n"); | 1350 | recv_from_streams (peer); |
1312 | return; | ||
1313 | } | 1351 | } |
1314 | } // null connection | 1352 | /** |
1315 | 1353 | * TODO: Should we use a list instead of hashmap? | |
1316 | quiche_recv_info recv_info = { | 1354 | * Overhead for hashing function, O(1) retrieval vs O(n) iteration with n=30? |
1317 | (struct sockaddr *) &sa, | 1355 | * |
1318 | salen, | 1356 | * TODO: Is iteration necessary as in the quiche server example? |
1319 | 1357 | */ | |
1320 | local_addr, | 1358 | quiche_stats stats; |
1321 | in_len, | 1359 | quiche_path_stats path_stats; |
1322 | }; | ||
1323 | process_pkt = quiche_conn_recv (peer->conn->conn, buf, rcvd, &recv_info); | ||
1324 | if (0 > process_pkt) | ||
1325 | { | ||
1326 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1327 | "quiche failed to process received packet: %zd\n", | ||
1328 | process_pkt); | ||
1329 | return; | ||
1330 | } | ||
1331 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1332 | "quiche processed %zd bytes\n", process_pkt); | ||
1333 | /** | ||
1334 | * Check for connection establishment | ||
1335 | */ | ||
1336 | if (quiche_conn_is_established (peer->conn->conn)) | ||
1337 | { | ||
1338 | // Check for data on all available streams | ||
1339 | recv_from_streams (peer); | ||
1340 | } | ||
1341 | /** | ||
1342 | * TODO: Should we use a list instead of hashmap? | ||
1343 | * Overhead for hashing function, O(1) retrieval vs O(n) iteration with n=30? | ||
1344 | * | ||
1345 | * TODO: Is iteration necessary as in the quiche server example? | ||
1346 | */ | ||
1347 | quiche_stats stats; | ||
1348 | quiche_path_stats path_stats; | ||
1349 | 1360 | ||
1350 | flush_egress (peer->conn); | 1361 | flush_egress (peer->conn); |
1351 | 1362 | ||
1352 | if (quiche_conn_is_closed (peer->conn->conn)) | 1363 | if (quiche_conn_is_closed (peer->conn->conn)) |
1353 | { | 1364 | { |
1354 | quiche_conn_stats (peer->conn->conn, &stats); | 1365 | quiche_conn_stats (peer->conn->conn, &stats); |
1355 | quiche_conn_path_stats (peer->conn->conn, 0, &path_stats); | 1366 | quiche_conn_path_stats (peer->conn->conn, 0, &path_stats); |
1356 | 1367 | ||
1357 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 1368 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
1358 | "connection closed. quiche stats: sent=%zu, recv=%zu\n", | 1369 | "connection closed. quiche stats: sent=%zu, recv=%zu\n", |
1359 | stats.sent, stats.recv); | 1370 | stats.sent, stats.recv); |
1360 | peer_destroy (peer); | 1371 | peer_destroy (peer); |
1372 | } | ||
1361 | } | 1373 | } |
1362 | GNUNET_free (local_addr); | 1374 | GNUNET_free (local_addr); |
1363 | } | 1375 | } |