aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormarshall <stmr@umich.edu>2023-07-26 21:39:21 -0400
committermarshall <stmr@umich.edu>2023-07-26 21:43:16 -0400
commitba23b260c2d3f9fb49fa438e69396c2f6284f97d (patch)
tree4fcd6ffd8f2daef5a95ce8ac3db3d03e7bf07665
parentc84e4e6467937abbd78e5aedd915597978915a49 (diff)
downloadgnunet-ba23b260c2d3f9fb49fa438e69396c2f6284f97d.tar.gz
gnunet-ba23b260c2d3f9fb49fa438e69396c2f6284f97d.zip
quic: optimize sock_read recv
-rw-r--r--src/transport/gnunet-communicator-quic.c346
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}