// File: ctz[P]openssl-bench/bench.cc
// Function: test_handshake_resume(unsigned int, Context&, Context&, bool)
static void test_handshake_resume(const unsigned n_threads, Context &server_ctx,
                                  Context &client_ctx,
                                  const bool with_tickets) {
  const size_t handshakes = apply_work_multiplier(4096);

  server_ctx.enable_resume();
  client_ctx.enable_resume();

  std::string prefix_server, prefix_client;

  if (!with_tickets) {
    server_ctx.disable_tickets();
    client_ctx.disable_tickets();
    prefix_server = "handshake-resume\tserver\t";
    prefix_client = "handshake-resume\tclient\t";

#ifdef BORINGSSL
    if (server_ctx.is_tls13()) {
      printf("!!! BoringSSL does not support stateful resumption for TLS1.3\n");
      return;
    }
#endif
  } else {
    prefix_server = "handshake-ticket\tserver\t";
    prefix_client = "handshake-ticket\tclient\t";
  }

  SSL_SESSION *client_session;

  {
    Conn initial_server(server_ctx.open());
    Conn initial_client(client_ctx.open());
    initial_client.set_sni("localhost");
    do_handshake(initial_client, initial_server);

    // pass some data to ensure ticket receipt
    initial_server.write((const uint8_t *)"hello", 5);
    initial_server.transfer_to(initial_client);

    uint8_t buf[5];
    initial_client.read(buf, 5);

    client_session = initial_client.get_session();
    assert(SSL_SESSION_is_resumable(client_session));
    initial_server.ragged_close();

    prefix_server += initial_client.get_cipher_string();
    prefix_client += initial_client.get_cipher_string();
  }

  client_ctx.bodge_disable_resume();

  std::vector<std::thread> threads;
  std::vector<Timings> results(n_threads);

  for (unsigned i = 0; i < n_threads; i++) {
    threads.push_back(std::thread(
        &test_handshake_resume_one, std::ref(results[i]), std::ref(server_ctx),
        std::ref(client_ctx), client_session, handshakes));
  }

  for (unsigned i = 0; i < n_threads; i++) {
    threads[i].join();
  }

  server_ctx.dump_sess_stats();
  print_results(prefix_server.c_str(), prefix_client.c_str(), results,
                handshakes, "handshakes/s");
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x1e0, %rsp            # imm = 0x1E0
movb %cl, %al
movl %edi, -0x4(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
andb $0x1, %al
movb %al, -0x19(%rbp)
movl $0x1000, %edi           # imm = 0x1000
callq 0x5340
movq %rax, -0x28(%rbp)
movq -0x10(%rbp), %rdi
callq 0xba40
movq -0x18(%rbp), %rdi
callq 0xba40
leaq -0x48(%rbp), %rdi
callq 0x3470
leaq -0x68(%rbp), %rdi
callq 0x3470
testb $0x1, -0x19(%rbp)
jne 0x4492
movq -0x10(%rbp), %rdi
callq 0xbaa0
jmp 0x4450
movq -0x18(%rbp), %rdi
callq 0xbaa0
jmp 0x445b
leaq 0xa154(%rip), %rsi      # 0xe5b6
leaq -0x48(%rbp), %rdi
callq 0x3460
jmp 0x446d
leaq 0xa15b(%rip), %rsi      # 0xe5cf
leaq -0x68(%rbp), %rdi
callq 0x3460
jmp 0x447f
jmp 0x44b8
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x70(%rbp)
movl %eax, -0x74(%rbp)
jmp 0x494c
leaq 0xa14f(%rip), %rsi      # 0xe5e8
leaq -0x48(%rbp), %rdi
callq 0x3460
jmp 0x44a4
leaq 0xa156(%rip), %rsi      # 0xe601
leaq -0x68(%rbp), %rdi
callq 0x3460
jmp 0x44b6
jmp 0x44b8
movq -0x10(%rbp), %rdi
callq 0x6500
movq %rax, -0x1a8(%rbp)
jmp 0x44ca
movq -0x1a8(%rbp), %rsi
leaq -0xb8(%rbp), %rdi
callq 0x6520
jmp 0x44df
movq -0x18(%rbp), %rdi
callq 0x6500
movq %rax, -0x1b0(%rbp)
jmp 0x44f1
movq -0x1b0(%rbp), %rsi
leaq -0xf0(%rbp), %rdi
callq 0x6520
jmp 0x4506
leaq 0x9eea(%rip), %rsi      # 0xe3f7
leaq -0xf0(%rbp), %rdi
callq 0xa9b0
jmp 0x451b
leaq -0xf0(%rbp), %rdi
leaq -0xb8(%rbp), %rsi
callq 0x5050
jmp 0x4530
leaq 0xa0e3(%rip), %rsi      # 0xe61a
leaq -0xb8(%rbp), %rdi
movl $0x5, %edx
callq 0x7af0
jmp 0x454a
leaq -0xb8(%rbp), %rdi
leaq -0xf0(%rbp), %rsi
callq 0x7b80
jmp 0x455f
leaq -0xf0(%rbp), %rdi
leaq -0xf5(%rbp), %rsi
movl $0x5, %edx
callq 0x7cb0
jmp 0x4579
leaq -0xf0(%rbp), %rdi
callq 0xbae0
movq %rax, -0x1b8(%rbp)
jmp 0x458e
movq -0x1b8(%rbp), %rax
movq %rax, -0x80(%rbp)
movq -0x80(%rbp), %rdi
callq 0x34b0
movl %eax, -0x1bc(%rbp)
jmp 0x45aa
movl -0x1bc(%rbp), %eax
cmpl $0x0, %eax
je 0x45b7
jmp 0x45f8
leaq 0xa062(%rip), %rdi      # 0xe620
leaq 0x9c1a(%rip), %rsi      # 0xe1df
movl $0x298, %edx            # imm = 0x298
leaq 0xa078(%rip), %rcx      # 0xe649
callq 0x3210
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x70(%rbp)
movl %eax, -0x74(%rbp)
jmp 0x47f5
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x70(%rbp)
movl %eax, -0x74(%rbp)
jmp 0x47e9
leaq -0xb8(%rbp), %rdi
callq 0xbb40
jmp 0x4606
leaq -0x118(%rbp), %rdi
leaq -0xf0(%rbp), %rsi
callq 0x6690
jmp 0x461b
leaq -0x48(%rbp), %rdi
leaq -0x118(%rbp), %rsi
callq 0x3440
jmp 0x462d
leaq -0x118(%rbp), %rdi
callq 0x31f0
leaq -0x138(%rbp), %rdi
leaq -0xf0(%rbp), %rsi
callq 0x6690
jmp 0x464e
leaq -0x68(%rbp), %rdi
leaq -0x138(%rbp), %rsi
callq 0x3440
jmp 0x4660
leaq -0x138(%rbp), %rdi
callq 0x31f0
leaq -0xf0(%rbp), %rdi
callq 0x6770
leaq -0xb8(%rbp), %rdi
callq 0x6770
movq -0x18(%rbp), %rdi
callq 0xbb70
jmp 0x468f
leaq -0x150(%rbp), %rdi
callq 0x6250
movl -0x4(%rbp), %eax
movq %rax, -0x1d0(%rbp)
leaq -0x169(%rbp), %rdi
movq %rdi, -0x1c8(%rbp)
callq 0x6270
movq -0x1d0(%rbp), %rsi
movq -0x1c8(%rbp), %rdx
leaq -0x168(%rbp), %rdi
callq 0x6290
jmp 0x46d4
leaq -0x169(%rbp), %rdi
callq 0x6300
movl $0x0, -0x170(%rbp)
movl -0x170(%rbp), %eax
cmpl -0x4(%rbp), %eax
jae 0x4851
leaq 0x1280(%rip), %rax      # 0x5980
movq %rax, -0x180(%rbp)
movl -0x170(%rbp), %eax
movl %eax, %esi
leaq -0x168(%rbp), %rdi
callq 0x6380
movq %rax, %rdi
callq 0x6350
movq %rax, -0x188(%rbp)
movq -0x10(%rbp), %rdi
callq 0x63a0
movq %rax, -0x190(%rbp)
movq -0x18(%rbp), %rdi
callq 0x63a0
movq %rax, -0x198(%rbp)
movq %rsp, %rax
leaq -0x28(%rbp), %rcx
movq %rcx, (%rax)
leaq -0x178(%rbp), %rdi
leaq -0x180(%rbp), %rsi
leaq -0x188(%rbp), %rdx
leaq -0x190(%rbp), %rcx
leaq -0x198(%rbp), %r8
leaq -0x80(%rbp), %r9
callq 0xbba0
jmp 0x4782
leaq -0x150(%rbp), %rdi
leaq -0x178(%rbp), %rsi
callq 0x6320
jmp 0x4797
leaq -0x178(%rbp), %rdi
callq 0x64b0
movl -0x170(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x170(%rbp)
jmp 0x46ea
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x70(%rbp)
movl %eax, -0x74(%rbp)
leaq -0x118(%rbp), %rdi
callq 0x31f0
jmp 0x47e9
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x70(%rbp)
movl %eax, -0x74(%rbp)
leaq -0x138(%rbp), %rdi
callq 0x31f0
leaq -0xf0(%rbp), %rdi
callq 0x6770
leaq -0xb8(%rbp), %rdi
callq 0x6770
jmp 0x494c
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x70(%rbp)
movl %eax, -0x74(%rbp)
leaq -0x169(%rbp), %rdi
callq 0x6300
jmp 0x4940
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x70(%rbp)
movl %eax, -0x74(%rbp)
jmp 0x4934
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x70(%rbp)
movl %eax, -0x74(%rbp)
leaq -0x178(%rbp), %rdi
callq 0x64b0
jmp 0x4934
movl $0x0, -0x19c(%rbp)
movl -0x19c(%rbp), %eax
cmpl -0x4(%rbp), %eax
jae 0x4897
movl -0x19c(%rbp), %eax
movl %eax, %esi
leaq -0x150(%rbp), %rdi
callq 0x64e0
movq %rax, %rdi
callq 0x3580
jmp 0x4884
jmp 0x4886
movl -0x19c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x19c(%rbp)
jmp 0x485b
movq -0x10(%rbp), %rdi
callq 0xbc80
jmp 0x48a2
leaq -0x48(%rbp), %rdi
callq 0x3160
movq %rax, -0x1d8(%rbp)
leaq -0x68(%rbp), %rdi
callq 0x3160
movq -0x1d8(%rbp), %rdi
movq %rax, %rsi
movaps 0x9744(%rip), %xmm1     # 0xe010
movq -0x28(%rbp), %xmm0
punpckldq %xmm1, %xmm0    # xmm0 = xmm0[0],xmm1[0],xmm0[1],xmm1[1]
movapd 0x9743(%rip), %xmm1     # 0xe020
subpd %xmm1, %xmm0
movaps %xmm0, %xmm1
unpckhpd %xmm0, %xmm0            # xmm0 = xmm0[1,1]
addsd %xmm1, %xmm0
leaq 0x9bb8(%rip), %rcx      # 0xe4ab
leaq -0x168(%rbp), %rdx
callq 0x5090
jmp 0x4901
leaq -0x168(%rbp), %rdi
callq 0x67c0
leaq -0x150(%rbp), %rdi
callq 0x6820
leaq -0x68(%rbp), %rdi
callq 0x31f0
leaq -0x48(%rbp), %rdi
callq 0x31f0
addq $0x1e0, %rsp            # imm = 0x1E0
popq %rbp
retq
leaq -0x168(%rbp), %rdi
callq 0x67c0
leaq -0x150(%rbp), %rdi
callq 0x6820
leaq -0x68(%rbp), %rdi
callq 0x31f0
leaq -0x48(%rbp), %rdi
callq 0x31f0
movq -0x70(%rbp), %rdi
callq 0x3590
nopw (%rax,%rax)