Skip to content

Commit bd5b9f4

Browse files
RUST-1894 Retry KMS requests on transient errors (#37)
1 parent 9da3d09 commit bd5b9f4

File tree

3 files changed

+53
-14
lines changed

3 files changed

+53
-14
lines changed

mongocrypt-sys/src/bindings.rs

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* automatically generated by rust-bindgen 0.63.0 */
1+
/* automatically generated by rust-bindgen 0.64.0 */
22

33
extern "C" {
44
#[doc = " Returns the version string for libmongocrypt.\n\n @param[out] len An optional length of the returned string. May be NULL.\n @returns a NULL terminated version string for libmongocrypt."]
@@ -158,6 +158,10 @@ extern "C" {
158158
log_ctx: *mut ::std::os::raw::c_void,
159159
) -> bool;
160160
}
161+
extern "C" {
162+
#[doc = " Enable or disable KMS retry behavior.\n\n @param[in] crypt The @ref mongocrypt_t object.\n @param[in] enable A boolean indicating whether to retry operations.\n @pre @ref mongocrypt_init has not been called on @p crypt.\n @returns A boolean indicating success. If false, an error status is set.\n Retrieve it with @ref mongocrypt_ctx_status"]
163+
pub fn mongocrypt_setopt_retry_kms(crypt: *mut mongocrypt_t, enable: bool) -> bool;
164+
}
161165
extern "C" {
162166
#[doc = " Configure an AWS KMS provider on the @ref mongocrypt_t object.\n\n This has been superseded by the more flexible:\n @ref mongocrypt_setopt_kms_providers\n\n @param[in] crypt The @ref mongocrypt_t object.\n @param[in] aws_access_key_id The AWS access key ID used to generate KMS\n messages.\n @param[in] aws_access_key_id_len The string length (in bytes) of @p\n aws_access_key_id. Pass -1 to determine the string length with strlen (must\n be NULL terminated).\n @param[in] aws_secret_access_key The AWS secret access key used to generate\n KMS messages.\n @param[in] aws_secret_access_key_len The string length (in bytes) of @p\n aws_secret_access_key. Pass -1 to determine the string length with strlen\n (must be NULL terminated).\n @pre @ref mongocrypt_init has not been called on @p crypt.\n @returns A boolean indicating success. If false, an error status is set.\n Retrieve it with @ref mongocrypt_ctx_status"]
163167
pub fn mongocrypt_setopt_kms_provider_aws(
@@ -238,7 +242,7 @@ extern "C" {
238242
) -> *const ::std::os::raw::c_char;
239243
}
240244
extern "C" {
241-
#[doc = " @brief Obtain a 64-bit constant encoding the version of the loaded\n crypt_shared library, if available.\n\n @param[in] crypt The mongocrypt_t object after a successul call to\n mongocrypt_init.\n\n @return A 64-bit encoded version number, with the version encoded as four\n sixteen-bit integers, or zero if no crypt_shared library was loaded.\n\n The version is encoded as four 16-bit numbers, from high to low:\n\n - Major version\n - Minor version\n - Revision\n - Reserved\n\n For example, version 6.2.1 would be encoded as: 0x0006'0002'0001'0000"]
245+
#[doc = " @brief Obtain a 64-bit constant encoding the version of the loaded\n crypt_shared library, if available.\n\n @param[in] crypt The mongocrypt_t object after a successful call to\n mongocrypt_init.\n\n @return A 64-bit encoded version number, with the version encoded as four\n sixteen-bit integers, or zero if no crypt_shared library was loaded.\n\n The version is encoded as four 16-bit numbers, from high to low:\n\n - Major version\n - Minor version\n - Revision\n - Reserved\n\n For example, version 6.2.1 would be encoded as: 0x0006'0002'0001'0000"]
242246
pub fn mongocrypt_crypt_shared_lib_version(crypt: *const mongocrypt_t) -> u64;
243247
}
244248
#[repr(C)]
@@ -411,7 +415,7 @@ pub struct _mongocrypt_kms_ctx_t {
411415
#[doc = " Manages a single KMS HTTP request/response."]
412416
pub type mongocrypt_kms_ctx_t = _mongocrypt_kms_ctx_t;
413417
extern "C" {
414-
#[doc = " Get the next KMS handle.\n\n Multiple KMS handles may be retrieved at once. Drivers may do this to fan\n out multiple concurrent KMS HTTP requests. Feeding multiple KMS requests\n is thread-safe.\n\n If KMS handles are being handled synchronously, the driver can reuse the same\n TLS socket to send HTTP requests and receive responses.\n\n @param[in] ctx A @ref mongocrypt_ctx_t.\n @returns a new @ref mongocrypt_kms_ctx_t or NULL."]
418+
#[doc = " Get the next KMS handle.\n\n Multiple KMS handles may be retrieved at once. Drivers may do this to fan\n out multiple concurrent KMS HTTP requests. Feeding multiple KMS requests\n is thread-safe.\n\n If KMS handles are being handled synchronously, the driver can reuse the same\n TLS socket to send HTTP requests and receive responses.\n\n The returned KMS handle does not outlive `ctx`.\n\n @param[in] ctx A @ref mongocrypt_ctx_t.\n @returns a new @ref mongocrypt_kms_ctx_t or NULL."]
415419
pub fn mongocrypt_ctx_next_kms_ctx(ctx: *mut mongocrypt_ctx_t) -> *mut mongocrypt_kms_ctx_t;
416420
}
417421
extern "C" {
@@ -432,13 +436,21 @@ extern "C" {
432436
#[doc = " Indicates how many bytes to feed into @ref mongocrypt_kms_ctx_feed.\n\n @param[in] kms The @ref mongocrypt_kms_ctx_t.\n @returns The number of requested bytes."]
433437
pub fn mongocrypt_kms_ctx_bytes_needed(kms: *mut mongocrypt_kms_ctx_t) -> u32;
434438
}
439+
extern "C" {
440+
#[doc = " Indicates how long to sleep before sending this request.\n\n @param[in] kms The @ref mongocrypt_kms_ctx_t.\n @returns How long to sleep in microseconds."]
441+
pub fn mongocrypt_kms_ctx_usleep(kms: *mut mongocrypt_kms_ctx_t) -> i64;
442+
}
435443
extern "C" {
436444
#[doc = " Feed bytes from the HTTP response.\n\n Feeding more bytes than what has been returned in @ref\n mongocrypt_kms_ctx_bytes_needed is an error.\n\n @param[in] kms The @ref mongocrypt_kms_ctx_t.\n @param[in] bytes The bytes to feed. The viewed data is copied. It is valid to\n destroy @p bytes with @ref mongocrypt_binary_destroy immediately after.\n @returns A boolean indicating success. If false, an error status is set.\n Retrieve it with @ref mongocrypt_kms_ctx_status"]
437445
pub fn mongocrypt_kms_ctx_feed(
438446
kms: *mut mongocrypt_kms_ctx_t,
439447
bytes: *mut mongocrypt_binary_t,
440448
) -> bool;
441449
}
450+
extern "C" {
451+
#[doc = " Indicate a network-level failure.\n\n @param[in] kms The @ref mongocrypt_kms_ctx_t.\n @return A boolean indicating whether the failed request may be retried."]
452+
pub fn mongocrypt_kms_ctx_fail(kms: *mut mongocrypt_kms_ctx_t) -> bool;
453+
}
442454
extern "C" {
443455
#[doc = " Get the status associated with a @ref mongocrypt_kms_ctx_t object.\n\n @param[in] kms The @ref mongocrypt_kms_ctx_t object.\n @param[out] status Receives the status.\n\n @returns A boolean indicating success. If false, an error status is set."]
444456
pub fn mongocrypt_kms_ctx_status(
@@ -475,7 +487,7 @@ extern "C" {
475487
#[doc = " Destroy and free all memory associated with a @ref mongocrypt_ctx_t.\n\n @param[in] ctx A @ref mongocrypt_ctx_t."]
476488
pub fn mongocrypt_ctx_destroy(ctx: *mut mongocrypt_ctx_t);
477489
}
478-
#[doc = " An crypto AES-256-CBC encrypt or decrypt function.\n\n Note, @p in is already padded. Encrypt with padding disabled.\n @param[in] ctx An optional context object that may have been set when hooks\n were enabled.\n @param[in] key An encryption key (32 bytes for AES_256).\n @param[in] iv An initialization vector (16 bytes for AES_256);\n @param[in] in The input.\n @param[out] out A preallocated byte array for the output. See @ref\n mongocrypt_binary_data.\n @param[out] bytes_written Set this to the number of bytes written to @p out.\n @param[out] status An optional status to pass error messages. See @ref\n mongocrypt_status_set.\n @returns A boolean indicating success. If returning false, set @p status\n with a message indiciating the error using @ref mongocrypt_status_set."]
490+
#[doc = " An crypto AES-256-CBC encrypt or decrypt function.\n\n Note, @p in is already padded. Encrypt with padding disabled.\n @param[in] ctx An optional context object that may have been set when hooks\n were enabled.\n @param[in] key An encryption key (32 bytes for AES_256).\n @param[in] iv An initialization vector (16 bytes for AES_256);\n @param[in] in The input.\n @param[out] out A preallocated byte array for the output. See @ref\n mongocrypt_binary_data.\n @param[out] bytes_written Set this to the number of bytes written to @p out.\n @param[out] status An optional status to pass error messages. See @ref\n mongocrypt_status_set.\n @returns A boolean indicating success. If returning false, set @p status\n with a message indicating the error using @ref mongocrypt_status_set."]
479491
pub type mongocrypt_crypto_fn = ::std::option::Option<
480492
unsafe extern "C" fn(
481493
ctx: *mut ::std::os::raw::c_void,
@@ -487,7 +499,7 @@ pub type mongocrypt_crypto_fn = ::std::option::Option<
487499
status: *mut mongocrypt_status_t,
488500
) -> bool,
489501
>;
490-
#[doc = " A crypto signature or HMAC function.\n\n Currently used in callbacks for HMAC SHA-512, HMAC SHA-256, and RSA SHA-256\n signature.\n\n @param[in] ctx An optional context object that may have been set when hooks\n were enabled.\n @param[in] key An encryption key (32 bytes for HMAC_SHA512).\n @param[in] in The input.\n @param[out] out A preallocated byte array for the output. See @ref\n mongocrypt_binary_data.\n @param[out] status An optional status to pass error messages. See @ref\n mongocrypt_status_set.\n @returns A boolean indicating success. If returning false, set @p status\n with a message indiciating the error using @ref mongocrypt_status_set."]
502+
#[doc = " A crypto signature or HMAC function.\n\n Currently used in callbacks for HMAC SHA-512, HMAC SHA-256, and RSA SHA-256\n signature.\n\n @param[in] ctx An optional context object that may have been set when hooks\n were enabled.\n @param[in] key An encryption key (32 bytes for HMAC_SHA512).\n @param[in] in The input.\n @param[out] out A preallocated byte array for the output. See @ref\n mongocrypt_binary_data.\n @param[out] status An optional status to pass error messages. See @ref\n mongocrypt_status_set.\n @returns A boolean indicating success. If returning false, set @p status\n with a message indicating the error using @ref mongocrypt_status_set."]
491503
pub type mongocrypt_hmac_fn = ::std::option::Option<
492504
unsafe extern "C" fn(
493505
ctx: *mut ::std::os::raw::c_void,
@@ -497,7 +509,7 @@ pub type mongocrypt_hmac_fn = ::std::option::Option<
497509
status: *mut mongocrypt_status_t,
498510
) -> bool,
499511
>;
500-
#[doc = " A crypto hash (SHA-256) function.\n\n @param[in] ctx An optional context object that may have been set when hooks\n were enabled.\n @param[in] in The input.\n @param[out] out A preallocated byte array for the output. See @ref\n mongocrypt_binary_data.\n @param[out] status An optional status to pass error messages. See @ref\n mongocrypt_status_set.\n @returns A boolean indicating success. If returning false, set @p status\n with a message indiciating the error using @ref mongocrypt_status_set."]
512+
#[doc = " A crypto hash (SHA-256) function.\n\n @param[in] ctx An optional context object that may have been set when hooks\n were enabled.\n @param[in] in The input.\n @param[out] out A preallocated byte array for the output. See @ref\n mongocrypt_binary_data.\n @param[out] status An optional status to pass error messages. See @ref\n mongocrypt_status_set.\n @returns A boolean indicating success. If returning false, set @p status\n with a message indicating the error using @ref mongocrypt_status_set."]
501513
pub type mongocrypt_hash_fn = ::std::option::Option<
502514
unsafe extern "C" fn(
503515
ctx: *mut ::std::os::raw::c_void,
@@ -506,7 +518,7 @@ pub type mongocrypt_hash_fn = ::std::option::Option<
506518
status: *mut mongocrypt_status_t,
507519
) -> bool,
508520
>;
509-
#[doc = " A crypto secure random function.\n\n @param[in] ctx An optional context object that may have been set when hooks\n were enabled.\n @param[out] out A preallocated byte array for the output. See @ref\n mongocrypt_binary_data.\n @param[in] count The number of random bytes requested.\n @param[out] status An optional status to pass error messages. See @ref\n mongocrypt_status_set.\n @returns A boolean indicating success. If returning false, set @p status\n with a message indiciating the error using @ref mongocrypt_status_set."]
521+
#[doc = " A crypto secure random function.\n\n @param[in] ctx An optional context object that may have been set when hooks\n were enabled.\n @param[out] out A preallocated byte array for the output. See @ref\n mongocrypt_binary_data.\n @param[in] count The number of random bytes requested.\n @param[out] status An optional status to pass error messages. See @ref\n mongocrypt_status_set.\n @returns A boolean indicating success. If returning false, set @p status\n with a message indicating the error using @ref mongocrypt_status_set."]
510522
pub type mongocrypt_random_fn = ::std::option::Option<
511523
unsafe extern "C" fn(
512524
ctx: *mut ::std::os::raw::c_void,
@@ -583,9 +595,16 @@ extern "C" {
583595
) -> bool;
584596
}
585597
extern "C" {
586-
#[doc = " Set options for explicit encryption with the \"range\" algorithm.\n\n @p opts is a BSON document of the form:\n {\n \"min\": Optional<BSON value>,\n \"max\": Optional<BSON value>,\n \"sparsity\": Int64,\n \"precision\": Optional<Int32>,\n \"trimFactor\": Optional<Int32>\n }\n\n @param[in] ctx The @ref mongocrypt_ctx_t object.\n @param[in] opts BSON.\n @pre @p ctx has not been initialized.\n @returns A boolean indicating success. If false, an error status is set.\n Retrieve it with @ref mongocrypt_ctx_status"]
598+
#[doc = " Set options for explicit encryption with the \"range\" algorithm.\n\n @p opts is a BSON document of the form:\n {\n \"min\": Optional<BSON value>,\n \"max\": Optional<BSON value>,\n \"sparsity\": Optional<Int64>,\n \"precision\": Optional<Int32>,\n \"trimFactor\": Optional<Int32>\n }\n\n @param[in] ctx The @ref mongocrypt_ctx_t object.\n @param[in] opts BSON.\n @pre @p ctx has not been initialized.\n @returns A boolean indicating success. If false, an error status is set.\n Retrieve it with @ref mongocrypt_ctx_status"]
587599
pub fn mongocrypt_ctx_setopt_algorithm_range(
588600
ctx: *mut mongocrypt_ctx_t,
589601
opts: *mut mongocrypt_binary_t,
590602
) -> bool;
591603
}
604+
extern "C" {
605+
#[doc = " Set the expiration time for the data encryption key cache. Defaults to 60 seconds if not set.\n\n @param[in] ctx The @ref mongocrypt_ctx_t object.\n @param[in] cache_expiration_ms The cache expiration time in milliseconds. If zero, the cache\n never expires."]
606+
pub fn mongocrypt_setopt_key_expiration(
607+
crypt: *mut mongocrypt_t,
608+
cache_expiration_ms: u64,
609+
) -> bool;
610+
}

mongocrypt/src/ctx.rs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,16 @@ impl<'scope> KmsCtx<'scope> {
702702
}
703703
}
704704

705+
/// How many microseconds to sleep before sending a request.
706+
pub fn sleep_micros(&self) -> i64 {
707+
unsafe { sys::mongocrypt_kms_ctx_usleep(self.inner) }
708+
}
709+
710+
/// Whether a failed request can be retried.
711+
pub fn retry_failure(&self) -> bool {
712+
unsafe { sys::mongocrypt_kms_ctx_fail(self.inner) }
713+
}
714+
705715
/// Indicates how many bytes to feed into `feed`.
706716
pub fn bytes_needed(&self) -> u32 {
707717
unsafe { sys::mongocrypt_kms_ctx_bytes_needed(self.inner) }
@@ -784,7 +794,7 @@ impl KmsProvider {
784794
pub fn local() -> Self {
785795
Self {
786796
provider_type: KmsProviderType::Local,
787-
name: None
797+
name: None,
788798
}
789799
}
790800

@@ -830,7 +840,8 @@ impl KmsProvider {
830840
KmsProviderType::Local => "local",
831841
KmsProviderType::Kmip => "kmip",
832842
KmsProviderType::Other(ref other) => other,
833-
}.to_string();
843+
}
844+
.to_string();
834845
if let Some(ref name) = self.name {
835846
full_name.push(':');
836847
full_name.push_str(name);
@@ -842,9 +853,7 @@ impl KmsProvider {
842853
/// type followed by an optional ":" and name, e.g. "aws" or "aws:name".
843854
pub fn from_string(name: &str) -> Self {
844855
let (provider_type, name) = match name.split_once(':') {
845-
Some((provider_type, name)) => {
846-
(provider_type, Some(name.to_string()))
847-
}
856+
Some((provider_type, name)) => (provider_type, Some(name.to_string())),
848857
None => (name, None),
849858
};
850859
let provider_type = match provider_type {
@@ -857,7 +866,7 @@ impl KmsProvider {
857866
};
858867
Self {
859868
provider_type,
860-
name
869+
name,
861870
}
862871
}
863872
}

mongocrypt/src/lib.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,17 @@ impl CryptBuilder {
248248
Ok(self)
249249
}
250250

251+
/// Enable or disable KMS retry behavior.
252+
pub fn retry_kms(self, enable: bool) -> Result<Self> {
253+
unsafe {
254+
let ok = sys::mongocrypt_setopt_retry_kms(*self.inner.borrow(), enable);
255+
if !ok {
256+
return Err(self.status().as_error())
257+
}
258+
}
259+
Ok(self)
260+
}
261+
251262
pub fn build(mut self) -> Result<Crypt> {
252263
let _guard = CRYPT_LOCK.lock().unwrap();
253264

0 commit comments

Comments
 (0)