(path: &str)
| 452 | } |
| 453 | |
| 454 | fn read_outblob_with_retry(path: &str) -> Result<Vec<u8>> { |
| 455 | const RETRY_WAIT_MS: u64 = 10000; |
| 456 | const MAX_RETRIES: usize = 3; |
| 457 | |
| 458 | let mut last_err = None; |
| 459 | for _ in 0..MAX_RETRIES { |
| 460 | let mut file = match File::open(path) { |
| 461 | Ok(f) => f, |
| 462 | Err(e) => { |
| 463 | last_err = Some(e); |
| 464 | continue; |
| 465 | } |
| 466 | }; |
| 467 | |
| 468 | let mut buf = vec![0u8; QUOTE_BUF_SIZE]; |
| 469 | match file.read(&mut buf) { |
| 470 | Ok(n) if n > 0 => { |
| 471 | buf.truncate(n); |
| 472 | return Ok(buf); |
| 473 | } |
| 474 | Ok(_) => { |
| 475 | return Err(TdxAttestError::QuoteFailure("empty outblob".to_string())); |
| 476 | } |
| 477 | Err(e) => { |
| 478 | let errno = e.raw_os_error().unwrap_or(0); |
| 479 | if errno == libc::EBUSY || errno == libc::EINTR || errno == libc::ETIMEDOUT { |
| 480 | thread::sleep(Duration::from_millis(RETRY_WAIT_MS)); |
| 481 | last_err = Some(e); |
| 482 | continue; |
| 483 | } |
| 484 | return Err(TdxAttestError::QuoteFailure(format!("read {path}: {e}"))); |
| 485 | } |
| 486 | } |
| 487 | } |
| 488 | |
| 489 | match last_err { |
| 490 | Some(e) if e.raw_os_error() == Some(libc::EBUSY) => Err(TdxAttestError::Busy), |
| 491 | Some(e) => Err(TdxAttestError::QuoteFailure(format!("read {path}: {e}"))), |
| 492 | None => Err(TdxAttestError::Unexpected("unknown error".to_string())), |
| 493 | } |
| 494 | } |
| 495 | |
| 496 | // ============================================================================ |
| 497 | // VSock Quote Generation (QGS Protocol) |
no test coverage detected