@@ -705,9 +705,9 @@ const uint8_t* picoquic_decode_retire_connection_id_frame(picoquic_cnx_t* cnx, c
705
705
picoquic_connection_error (cnx , PICOQUIC_TRANSPORT_FRAME_FORMAT_ERROR ,
706
706
(is_mp )?picoquic_frame_type_path_retire_connection_id :picoquic_frame_type_retire_connection_id );
707
707
}
708
- else if (path_x -> p_local_cnxid != NULL &&
708
+ else if (path_x -> first_tuple -> p_local_cnxid != NULL &&
709
709
(!is_mp || path_x -> unique_path_id == unique_path_id ) &&
710
- sequence == path_x -> p_local_cnxid -> sequence ) {
710
+ sequence == path_x -> first_tuple -> p_local_cnxid -> sequence ) {
711
711
/* Cannot delete the path through which it arrives */
712
712
picoquic_connection_error (cnx , PICOQUIC_TRANSPORT_PROTOCOL_VIOLATION ,
713
713
(is_mp ) ? picoquic_frame_type_path_retire_connection_id : picoquic_frame_type_retire_connection_id );
@@ -3822,17 +3822,13 @@ uint8_t* picoquic_format_ack_frame_in_context(picoquic_cnx_t* cnx, uint8_t* byte
3822
3822
(((is_ecn ) ? picoquic_frame_type_path_ack_ecn : picoquic_frame_type_path_ack ));
3823
3823
3824
3824
/* Check that there something to acknowledge */
3825
- #if 1
3826
3825
int not_needed = picoquic_sack_list_is_empty (& ack_ctx -> sack_list );
3827
3826
if (!not_needed && !ack_ctx -> act [is_opportunistic ].ack_needed &&
3828
3827
ack_ctx -> sack_list .ack_tree .size == 1 ) {
3829
3828
picoquic_sack_item_t * last_sack = picoquic_sack_last_item (& ack_ctx -> sack_list );
3830
3829
not_needed = (last_sack -> nb_times_sent [is_opportunistic ] >= PICOQUIC_MAX_ACK_RANGE_REPEAT );
3831
3830
}
3832
3831
if (!not_needed ){
3833
- #else
3834
- if (!picoquic_sack_list_is_empty (& ack_ctx -> sack_list )) {
3835
- #endif
3836
3832
uint8_t * num_block_byte = NULL ;
3837
3833
picoquic_sack_item_t * last_sack = picoquic_sack_last_item (& ack_ctx -> sack_list );
3838
3834
@@ -4031,9 +4027,9 @@ uint64_t picoquic_ack_gap_override_if_needed(picoquic_cnx_t* cnx, int path_index
4031
4027
uint64_t ack_gap = cnx -> ack_gap_remote ;
4032
4028
if (cnx -> is_multipath_enabled ) {
4033
4029
if (!cnx -> path [path_index ]-> path_is_demoted &&
4034
- !cnx -> path [path_index ]-> challenge_failed &&
4035
- !cnx -> path [path_index ]-> response_required &&
4036
- cnx -> path [path_index ]-> challenge_verified &&
4030
+ !cnx -> path [path_index ]-> first_tuple -> challenge_failed &&
4031
+ !cnx -> path [path_index ]-> first_tuple -> response_required &&
4032
+ cnx -> path [path_index ]-> first_tuple -> challenge_verified &&
4037
4033
cnx -> path [path_index ]-> received < 100 * PICOQUIC_MAX_PACKET_SIZE ) {
4038
4034
ack_gap = 2 ;
4039
4035
}
@@ -4652,26 +4648,30 @@ const uint8_t* picoquic_decode_path_challenge_frame(picoquic_cnx_t* cnx, const u
4652
4648
if (!is_valid ) {
4653
4649
/* If multipath is not enabled, we must verify that the addresses
4654
4650
* source (addr_from) matches the peer address if known. */
4655
- if (addr_from == NULL ||
4656
- picoquic_compare_addr (addr_from , (struct sockaddr * )& path_x -> first_tuple -> peer_addr ) == 0 ) {
4657
- /* If the source address matches, we must verify that the destination
4658
- * address also matches. Given how the socket code works there will be cases
4659
- * when the local port is now yet known. In that case, we only compare
4660
- * the IP address component . Otherwise, we compare the whole address.
4661
- */
4662
- if (addr_to == NULL ||
4663
- (picoquic_get_addr_port ((struct sockaddr * )& path_x -> first_tuple -> local_addr ) == 0 &&
4664
- picoquic_compare_ip_addr (addr_to , (struct sockaddr * )& path_x -> first_tuple -> local_addr ) == 0 ) ||
4665
- picoquic_compare_addr (addr_to , (struct sockaddr * )& path_x -> first_tuple -> local_addr ) == 0 ) {
4666
- is_valid = 1 ;
4651
+ picoquic_tuple_t * tuple = path_x -> first_tuple ;
4652
+ while (tuple != NULL ) {
4653
+
4654
+ if (addr_from == NULL ||
4655
+ picoquic_compare_addr (addr_from , (struct sockaddr * )& tuple -> peer_addr ) == 0 ) {
4656
+ /* If the source address matches, we must verify that the destination
4657
+ * address also matches. Given how the socket code works there will be cases
4658
+ * when the local port is now yet known. In that case, we only compare
4659
+ * the IP address component . Otherwise, we compare the whole address.
4660
+ */
4661
+ if (addr_to == NULL ||
4662
+ (picoquic_get_addr_port ((struct sockaddr * )& tuple -> local_addr ) == 0 &&
4663
+ picoquic_compare_ip_addr (addr_to , (struct sockaddr * )& tuple -> local_addr ) == 0 ) ||
4664
+ picoquic_compare_addr (addr_to , (struct sockaddr * )& tuple -> local_addr ) == 0 ) {
4665
+ is_valid = 1 ;
4666
+ tuple -> challenge_response = challenge_response ;
4667
+ tuple -> response_required = 1 ;
4668
+ break ;
4669
+ }
4667
4670
}
4671
+ tuple = tuple -> next_tuple ;
4668
4672
}
4669
4673
}
4670
- if (is_valid ) {
4671
- path_x -> first_tuple -> challenge_response = challenge_response ;
4672
- path_x -> response_required = 1 ;
4673
- }
4674
- else {
4674
+ if (!is_valid ) {
4675
4675
char buf1 [128 ], buf2 [128 ], buf3 [128 ], buf4 [128 ];
4676
4676
picoquic_log_app_message (cnx ,
4677
4677
"Path challenge[%" PRIu64 "] from %s to %s ignored, wrong addresses, expected %s - %s.\n" ,
@@ -4714,54 +4714,45 @@ const uint8_t* picoquic_decode_path_response_frame(picoquic_cnx_t* cnx, const ui
4714
4714
/* Per QUIC V1, path responses must come on the same path. Ignore them if this cannot be verified. */
4715
4715
if (path_x != NULL ) {
4716
4716
int found_challenge = 0 ;
4717
- int found_nat_challenge = 0 ;
4717
+ picoquic_tuple_t * tuple = path_x -> first_tuple ;
4718
+ picoquic_tuple_t * previous_tuple = NULL ;
4718
4719
4719
- for (int ichal = 0 ; ichal < PICOQUIC_CHALLENGE_REPEAT_MAX ; ichal ++ ) {
4720
- if (response == path_x -> first_tuple -> challenge [ichal ]) {
4721
- found_challenge = 1 ;
4722
- break ;
4723
- }
4724
- }
4725
- if (!found_challenge && path_x -> nat_peer_addr .ss_family != AF_UNSPEC ) {
4720
+ while (tuple != NULL ) {
4726
4721
for (int ichal = 0 ; ichal < PICOQUIC_CHALLENGE_REPEAT_MAX ; ichal ++ ) {
4727
- if (response == path_x -> nat_challenge [ichal ]) {
4728
- found_nat_challenge = 1 ;
4722
+ if (response == tuple -> challenge [ichal ]) {
4723
+ found_challenge = 1 ;
4729
4724
break ;
4730
4725
}
4731
4726
}
4732
- }
4733
- if (found_nat_challenge && !path_x -> challenge_verified ) {
4734
- /* while probing NAT, the NAT response arrived before the normal path response */
4735
- /* Update the addresses */
4736
- picoquic_store_addr (& path_x -> first_tuple -> local_addr , (struct sockaddr * )& path_x -> nat_local_addr );
4737
- picoquic_update_peer_addr (path_x , (struct sockaddr * )& path_x -> nat_peer_addr );
4738
- path_x -> first_tuple -> if_index_dest = path_x -> if_index_nat_dest ;
4739
- /* if useful, update the CID */
4740
- if (path_x -> p_remote_nat_cnxid != NULL ) {
4741
- picoquic_dereference_stashed_cnxid (cnx , path_x , 0 );
4742
- path_x -> p_remote_cnxid = path_x -> p_remote_nat_cnxid ;
4743
- path_x -> p_remote_nat_cnxid = NULL ;
4727
+ if (found_challenge ) {
4728
+ break ;
4744
4729
}
4745
- /* Consider this a successful challenge */
4746
- found_challenge = 1 ;
4730
+ previous_tuple = tuple ;
4731
+ tuple = tuple -> next_tuple ;
4747
4732
}
4748
4733
4749
- if (found_challenge && !path_x -> challenge_verified ){
4750
- /* TODO: update the RTT if using initial value */
4751
- path_x -> challenge_verified = 1 ;
4752
-
4734
+ if (found_challenge && !tuple -> challenge_verified ) {
4735
+ tuple -> challenge_verified = 1 ;
4753
4736
/* Provide a qualified time estimate from challenge time */
4754
- picoquic_update_path_rtt (cnx , path_x , path_x , -1 , path_x -> first_tuple -> challenge_time_first , current_time , 0 , 0 );
4755
-
4756
- if (cnx -> are_path_callbacks_enabled &&
4757
- cnx -> callback_fn (cnx , path_x -> unique_path_id , NULL , 0 , picoquic_callback_path_available ,
4758
- cnx -> callback_ctx , path_x -> app_path_ctx ) != 0 ) {
4759
- picoquic_connection_error_ex (cnx , PICOQUIC_TRANSPORT_INTERNAL_ERROR ,
4760
- picoquic_frame_type_path_response , "path available callback" );
4761
- bytes = NULL ;
4737
+ picoquic_update_path_rtt (cnx , path_x , path_x , -1 , tuple -> challenge_time_first , current_time , 0 , 0 );
4738
+ /* This challenge is verified.
4739
+ * If this is a client, the path should replace the current path.
4740
+ * If this is a server, the replacement should happen if we have a NAT, maybe,
4741
+ * or if qualifying data is received, which will happen later.
4742
+ */
4743
+ if (previous_tuple != NULL /* && cnx->client_mode */ ) {
4744
+ previous_tuple -> next_tuple = tuple -> next_tuple ;
4745
+ tuple -> next_tuple = path_x -> first_tuple ;
4746
+ path_x -> first_tuple = tuple ;
4747
+
4748
+ if (cnx -> are_path_callbacks_enabled &&
4749
+ cnx -> callback_fn (cnx , path_x -> unique_path_id , NULL , 0 , picoquic_callback_path_available ,
4750
+ cnx -> callback_ctx , path_x -> app_path_ctx ) != 0 ) {
4751
+ picoquic_connection_error_ex (cnx , PICOQUIC_TRANSPORT_INTERNAL_ERROR ,
4752
+ picoquic_frame_type_path_response , "path available callback" );
4753
+ bytes = NULL ;
4754
+ }
4762
4755
}
4763
- /* Erase the NAT address, to avoid continuing the NAT challenge */
4764
- path_x -> nat_peer_addr .ss_family = AF_UNSPEC ;
4765
4756
}
4766
4757
}
4767
4758
}
@@ -4795,8 +4786,8 @@ int picoquic_should_repeat_path_response_frame(picoquic_cnx_t* cnx, const uint8_
4795
4786
}
4796
4787
4797
4788
if (path_index >= 0 &&
4798
- (cnx -> path [path_index ]-> challenge_verified ||
4799
- (cnx -> client_mode && !cnx -> path [path_index ]-> challenge_failed ))) {
4789
+ (cnx -> path [path_index ]-> first_tuple -> challenge_verified ||
4790
+ (cnx -> client_mode && !cnx -> path [path_index ]-> first_tuple -> challenge_failed ))) {
4800
4791
should_repeat = 1 ;
4801
4792
}
4802
4793
else {
@@ -5549,7 +5540,7 @@ int picoquic_queue_path_available_or_backup_frame(
5549
5540
{
5550
5541
int ret = 0 ;
5551
5542
5552
- if (path_x -> p_remote_cnxid == NULL ) {
5543
+ if (path_x -> first_tuple -> p_remote_cnxid == NULL ) {
5553
5544
ret = -1 ;
5554
5545
}
5555
5546
else {
@@ -5560,7 +5551,7 @@ int picoquic_queue_path_available_or_backup_frame(
5560
5551
uint64_t sequence = cnx -> status_sequence_to_send_next ++ ;
5561
5552
uint64_t path_id = (cnx -> is_multipath_enabled )?
5562
5553
path_x -> unique_path_id :
5563
- path_x -> p_remote_cnxid -> sequence ;
5554
+ path_x -> first_tuple -> p_remote_cnxid -> sequence ;
5564
5555
int is_pure_ack = 0 ;
5565
5556
int more_data = 0 ;
5566
5557
uint8_t * bytes_next = picoquic_format_path_available_or_backup_frame (
@@ -6071,21 +6062,24 @@ uint8_t* picoquic_format_observed_address_frame(
6071
6062
return bytes ;
6072
6063
}
6073
6064
6065
+
6066
+
6074
6067
uint8_t * picoquic_prepare_observed_address_frame (uint8_t * bytes , const uint8_t * bytes_max ,
6075
- picoquic_path_t * path_x , uint64_t current_time , uint64_t * next_wake_time ,
6068
+ picoquic_path_t * path_x , picoquic_tuple_t * tuple ,
6069
+ uint64_t current_time , uint64_t * next_wake_time ,
6076
6070
int * more_data , int * is_pure_ack )
6077
6071
{
6078
- if (!path_x -> observed_addr_acked &&
6079
- path_x -> nb_observed_repeat < 4 &&
6080
- path_x -> first_tuple -> peer_addr .ss_family != AF_UNSPEC ) {
6072
+ if (!path_x -> observed_addr_acked &&
6073
+ tuple -> nb_observed_repeat < 4 &&
6074
+ tuple -> peer_addr .ss_family != AF_UNSPEC ) {
6081
6075
int is_needed = 0 ;
6082
6076
6083
- if (path_x -> nb_observed_repeat == 0 ) {
6077
+ if (tuple -> nb_observed_repeat == 0 ) {
6084
6078
is_needed = 1 ;
6085
6079
path_x -> observed_sequence_sent = path_x -> cnx -> observed_number ++ ;
6086
6080
}
6087
6081
else {
6088
- uint64_t repeat_time = path_x -> observed_time + path_x -> retransmit_timer ;
6082
+ uint64_t repeat_time = tuple -> observed_time + path_x -> retransmit_timer ;
6089
6083
6090
6084
if (repeat_time <= current_time ) {
6091
6085
is_needed = 1 ;
@@ -6100,14 +6094,14 @@ uint8_t* picoquic_prepare_observed_address_frame(uint8_t* bytes, const uint8_t*
6100
6094
uint8_t * ip_addr = NULL ;
6101
6095
uint16_t port = 0 ;
6102
6096
6103
- if (path_x -> first_tuple -> peer_addr .ss_family == AF_INET6 ) {
6104
- struct sockaddr_in6 * addr = (struct sockaddr_in6 * )& path_x -> first_tuple -> peer_addr ;
6097
+ if (tuple -> peer_addr .ss_family == AF_INET6 ) {
6098
+ struct sockaddr_in6 * addr = (struct sockaddr_in6 * )& tuple -> peer_addr ;
6105
6099
ftype = picoquic_frame_type_observed_address_v6 ;
6106
6100
ip_addr = (uint8_t * )& addr -> sin6_addr ;
6107
6101
port = ntohs (addr -> sin6_port );
6108
6102
}
6109
6103
else {
6110
- struct sockaddr_in * addr = (struct sockaddr_in * )& path_x -> first_tuple -> peer_addr ;
6104
+ struct sockaddr_in * addr = (struct sockaddr_in * )& tuple -> peer_addr ;
6111
6105
ftype = picoquic_frame_type_observed_address_v4 ;
6112
6106
ip_addr = (uint8_t * )& addr -> sin_addr ;
6113
6107
port = ntohs (addr -> sin_port );
@@ -6119,8 +6113,8 @@ uint8_t* picoquic_prepare_observed_address_frame(uint8_t* bytes, const uint8_t*
6119
6113
if (bytes_next > bytes ) {
6120
6114
* is_pure_ack = 0 ;
6121
6115
bytes = bytes_next ;
6122
- path_x -> nb_observed_repeat += 1 ;
6123
- path_x -> observed_time = current_time ;
6116
+ tuple -> nb_observed_repeat += 1 ;
6117
+ tuple -> observed_time = current_time ;
6124
6118
}
6125
6119
}
6126
6120
}
@@ -6208,6 +6202,7 @@ int picoquic_process_ack_of_observed_address_frame(picoquic_cnx_t* cnx, picoquic
6208
6202
ret = -1 ;
6209
6203
}
6210
6204
else {
6205
+ /* TODO: tie this to a specific address and port */
6211
6206
path_x -> observed_addr_acked = 1 ;
6212
6207
* consumed = bytes_next - bytes ;
6213
6208
}
0 commit comments