@@ -527,6 +527,27 @@ _get_stream (const char *endpoint, int32_t connecttimeoutms, const mongoc_ssl_op
527
527
return tls_stream ;
528
528
}
529
529
530
+ static int64_t
531
+ backoff_time_usec (int64_t attempts )
532
+ {
533
+ static bool seeded = false;
534
+ if (!seeded ) {
535
+ srand ((uint32_t ) time (NULL ));
536
+ seeded = true;
537
+ }
538
+
539
+ /* Exponential backoff with jitter. */
540
+ const int64_t base = 200000 ; /* 0.2 seconds */
541
+ const int64_t max = 20000000 ; /* 20 seconds */
542
+ int64_t backoff = base * (1LL << (attempts - 1 ));
543
+ if (backoff > max ) {
544
+ backoff = max ;
545
+ }
546
+
547
+ /* Full jitter: between 1 and current max */
548
+ return (int64_t ) ((double ) rand () / (double ) RAND_MAX * (double ) backoff ) + 1 ;
549
+ }
550
+
530
551
static bool
531
552
_state_need_kms (_state_machine_t * state_machine , bson_error_t * error )
532
553
{
@@ -575,94 +596,93 @@ _state_need_kms (_state_machine_t *state_machine, bson_error_t *error)
575
596
}
576
597
577
598
retry :
578
- while (true) {
579
- mongoc_stream_destroy (tls_stream );
580
- tls_stream = _get_stream (endpoint , sockettimeout , ssl_opt , error );
599
+ if (retry_count > 0 ) {
600
+ int64_t sleep_usec = backoff_time_usec (retry_count );
601
+ _mongoc_usleep (sleep_usec );
602
+ }
603
+
604
+ mongoc_stream_destroy (tls_stream );
605
+ tls_stream = _get_stream (endpoint , sockettimeout , ssl_opt , error );
581
606
#ifdef MONGOC_ENABLE_SSL_SECURE_CHANNEL
582
- /* Retry once with schannel as a workaround for CDRIVER-3566. */
583
- if (!tls_stream ) {
584
- tls_stream = _get_stream (endpoint , sockettimeout , ssl_opt , error );
585
- }
607
+ /* Retry once with schannel as a workaround for CDRIVER-3566. */
608
+ if (!tls_stream ) {
609
+ tls_stream = _get_stream (endpoint , sockettimeout , ssl_opt , error );
610
+ }
586
611
#endif
587
- if (!tls_stream ) {
588
- retry_count ++ ;
589
- if (retry_count < max_tcp_retries ) {
590
- /* Always safe to retry stream creation. */
591
- continue ;
592
- } else {
593
- /* TLS errors are set in _get_stream */
594
- goto fail ;
595
- }
612
+ if (!tls_stream ) {
613
+ retry_count ++ ;
614
+ if (retry_count < max_tcp_retries ) {
615
+ /* Always safe to retry stream creation. */
616
+ goto retry ;
617
+ } else {
618
+ /* TLS errors are set in _get_stream */
619
+ goto fail ;
596
620
}
621
+ }
597
622
598
- iov .iov_base = (char * ) mongocrypt_binary_data (http_req );
599
- iov .iov_len = mongocrypt_binary_len (http_req );
623
+ iov .iov_base = (char * ) mongocrypt_binary_data (http_req );
624
+ iov .iov_len = mongocrypt_binary_len (http_req );
600
625
601
- if (!_mongoc_stream_writev_full (tls_stream , & iov , 1 , sockettimeout , error )) {
602
- retry_count ++ ;
603
- if (retry_count < max_tcp_retries ) {
604
- /* Always safe to retry unsuccessful writes. */
605
- continue ;
606
- } else {
607
- bson_set_error (error ,
608
- MONGOC_ERROR_STREAM ,
609
- MONGOC_ERROR_STREAM_SOCKET ,
610
- "Failed to write to KMS stream: %s" ,
611
- endpoint );
612
- goto fail ;
613
- }
626
+ if (!_mongoc_stream_writev_full (tls_stream , & iov , 1 , sockettimeout , error )) {
627
+ retry_count ++ ;
628
+ if (retry_count < max_tcp_retries && mongocrypt_kms_ctx_fail (kms_ctx )) {
629
+ goto retry ;
630
+ } else {
631
+ bson_set_error (
632
+ error , MONGOC_ERROR_STREAM , MONGOC_ERROR_STREAM_SOCKET , "Failed to write to KMS stream: %s" , endpoint );
633
+ goto fail ;
614
634
}
635
+ }
615
636
616
- /* Read and feed reply. */
617
- while (mongocrypt_kms_ctx_bytes_needed (kms_ctx ) > 0 ) {
637
+ /* Read and feed reply. */
638
+ while (mongocrypt_kms_ctx_bytes_needed (kms_ctx ) > 0 ) {
618
639
#define BUFFER_SIZE 1024
619
- uint8_t buf [BUFFER_SIZE ];
620
- uint32_t bytes_needed = mongocrypt_kms_ctx_bytes_needed (kms_ctx );
621
- ssize_t read_ret ;
640
+ uint8_t buf [BUFFER_SIZE ];
641
+ uint32_t bytes_needed = mongocrypt_kms_ctx_bytes_needed (kms_ctx );
642
+ ssize_t read_ret ;
622
643
623
- int64_t sleep_usec = mongocrypt_kms_ctx_usleep (kms_ctx );
624
- if (sleep_usec > 0 ) {
625
- _mongoc_usleep (sleep_usec );
626
- }
644
+ int64_t sleep_usec = mongocrypt_kms_ctx_usleep (kms_ctx );
645
+ if (sleep_usec > 0 ) {
646
+ _mongoc_usleep (sleep_usec );
647
+ }
627
648
628
- /* Cap the bytes requested at the buffer size. */
629
- if (bytes_needed > BUFFER_SIZE ) {
630
- bytes_needed = BUFFER_SIZE ;
631
- }
649
+ /* Cap the bytes requested at the buffer size. */
650
+ if (bytes_needed > BUFFER_SIZE ) {
651
+ bytes_needed = BUFFER_SIZE ;
652
+ }
632
653
633
- read_ret = mongoc_stream_read (tls_stream , buf , bytes_needed , 1 /* min_bytes. */ , sockettimeout );
634
- if (read_ret <= 0 ) {
635
- retry_count ++ ;
636
- if (retry_count < max_tcp_retries && mongocrypt_kms_ctx_fail (kms_ctx )) {
637
- goto retry ;
654
+ read_ret = mongoc_stream_read (tls_stream , buf , bytes_needed , 1 /* min_bytes. */ , sockettimeout );
655
+ if (read_ret <= 0 ) {
656
+ retry_count ++ ;
657
+ if (retry_count < max_tcp_retries && mongocrypt_kms_ctx_fail (kms_ctx )) {
658
+ goto retry ;
659
+ } else {
660
+ if (read_ret == -1 ) {
661
+ bson_set_error (error ,
662
+ MONGOC_ERROR_STREAM ,
663
+ MONGOC_ERROR_STREAM_SOCKET ,
664
+ "failed to read from KMS stream: %d" ,
665
+ errno );
666
+ goto fail ;
638
667
} else {
639
- if (read_ret == -1 ) {
640
- bson_set_error (error ,
641
- MONGOC_ERROR_STREAM ,
642
- MONGOC_ERROR_STREAM_SOCKET ,
643
- "failed to read from KMS stream: %d" ,
644
- errno );
645
- goto fail ;
646
- } else {
647
- bson_set_error (
648
- error , MONGOC_ERROR_STREAM , MONGOC_ERROR_STREAM_SOCKET , "unexpected EOF from KMS stream" );
649
- goto fail ;
650
- }
668
+ bson_set_error (
669
+ error , MONGOC_ERROR_STREAM , MONGOC_ERROR_STREAM_SOCKET , "unexpected EOF from KMS stream" );
670
+ goto fail ;
651
671
}
652
672
}
653
- mongocrypt_binary_destroy (http_reply );
673
+ }
674
+ mongocrypt_binary_destroy (http_reply );
654
675
655
- BSON_ASSERT (bson_in_range_signed (uint32_t , read_ret ));
656
- http_reply = mongocrypt_binary_new_from_data (buf , (uint32_t ) read_ret );
657
- if (!mongocrypt_kms_ctx_feed (kms_ctx , http_reply )) {
658
- _kms_ctx_check_error (kms_ctx , error , true);
659
- goto fail ;
660
- }
676
+ BSON_ASSERT (bson_in_range_signed (uint32_t , read_ret ));
677
+ http_reply = mongocrypt_binary_new_from_data (buf , (uint32_t ) read_ret );
678
+ if (!mongocrypt_kms_ctx_feed (kms_ctx , http_reply )) {
679
+ _kms_ctx_check_error (kms_ctx , error , true);
680
+ goto fail ;
661
681
}
662
- kms_ctx = mongocrypt_ctx_next_kms_ctx (state_machine -> ctx );
663
- retry_count = 0 ;
664
- break ;
665
682
}
683
+ kms_ctx = mongocrypt_ctx_next_kms_ctx (state_machine -> ctx );
684
+ retry_count = 0 ;
685
+ break ;
666
686
}
667
687
/* When NULL is returned by mongocrypt_ctx_next_kms_ctx, this can either be
668
688
* an error or end-of-list. */
0 commit comments