// File: nvanbenschoten[P]total-order-multicast/src/udp_conn.cc
// Function: udp::Client::SendWithAck(char const*, unsigned long, unsigned int, std::function<udp::ServerAction (std::shared_ptr<udp::Client>, char*, unsigned long)>)
void Client::SendWithAck(const char *buf, size_t size, unsigned int attempts,
                         OnReceiveFn validAck) {
  std::lock_guard<std::recursive_mutex> guard(sockfd_mutex_);
  unsigned int backoff_mult = 1;
  bool noLimit = attempts == kUnlimitedAttempts;
  for (; noLimit || attempts > 0; --attempts) {
    // Send the message to the client.
    Send(buf, size);

    // Create a zeroed out buffer to read the ack message into.
    char ackbuf[BUFSIZE];
    bzero(ackbuf, BUFSIZE);

    // receive from the socket.
    struct sockaddr_in clientaddr;
    socklen_t clientlen = sizeof(clientaddr);
    int n = recvfrom(sockfd_, ackbuf, BUFSIZE, 0,
                     (struct sockaddr *)&clientaddr, &clientlen);

    // Check for error cases. This is either a timeout or some kind of
    // networking error. For timeouts, try sending the message again. For
    // anything else, throw an exception.
    if (n < 0) {
      if (IsErrnoTimeout()) {
        // Wait for a backoff period.
        WaitBackoff(backoff_mult);
        if (backoff_mult < kMaxBackoffMultiplier) {
          backoff_mult <<= 1;
        }
        continue;
      } else {
        throw net::ReceiveException();
      }
    }

    // Make sure the ack was valid.
    auto action = validAck(shared_from_this(), ackbuf, n);
    if (action == ServerAction::Stop) {
      return;
    }
  }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x4e0, %rsp            # imm = 0x4E0
movq %r8, -0x498(%rbp)
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movl %ecx, -0x1c(%rbp)
movq %r8, -0x28(%rbp)
movq -0x8(%rbp), %rsi
movq %rsi, -0x490(%rbp)
addq $0x10, %rsi
leaq -0x30(%rbp), %rdi
callq 0x2c880
movl $0x1, -0x34(%rbp)
cmpl $0x0, -0x1c(%rbp)
sete %al
andb $0x1, %al
movb %al, -0x35(%rbp)
movb $0x1, %al
testb $0x1, -0x35(%rbp)
movb %al, -0x499(%rbp)
jne 0x2befb
cmpl $0x0, -0x1c(%rbp)
seta %al
movb %al, -0x499(%rbp)
movb -0x499(%rbp), %al
testb $0x1, %al
jne 0x2bf0a
jmp 0x2c0e4
movq -0x490(%rbp), %rdi
movq -0x10(%rbp), %rsi
movq -0x18(%rbp), %rdx
callq 0x2bd80
jmp 0x2bf20
leaq -0x450(%rbp), %rdi
movq %rdi, -0x4c0(%rbp)
xorl %esi, %esi
movl %esi, -0x4ac(%rbp)
movl $0x400, %edx            # imm = 0x400
movq %rdx, -0x4b8(%rbp)
callq 0x6260
movq -0x4c0(%rbp), %rsi
movq -0x4b8(%rbp), %rdx
movl -0x4ac(%rbp), %ecx
movq -0x490(%rbp), %rax
movl $0x10, -0x464(%rbp)
movl 0x38(%rax), %edi
leaq -0x460(%rbp), %r8
leaq -0x464(%rbp), %r9
callq 0x6340
movq %rax, -0x4a8(%rbp)
jmp 0x2bf8b
movq -0x4a8(%rbp), %rax
movl %eax, -0x468(%rbp)
cmpl $0x0, -0x468(%rbp)
jge 0x2c04f
callq 0x2c9a0
movb %al, -0x4c1(%rbp)
jmp 0x2bfb2
movb -0x4c1(%rbp), %al
testb $0x1, %al
jne 0x2bfbe
jmp 0x2bff5
movq -0x490(%rbp), %rdi
movl -0x34(%rbp), %esi
callq 0x2c120
jmp 0x2bfcf
cmpl $0x40, -0x34(%rbp)
jae 0x2bff0
movl -0x34(%rbp), %eax
shll %eax
movl %eax, -0x34(%rbp)
jmp 0x2bff0
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
jmp 0x2c100
jmp 0x2c0d6
movl $0x180, %edi            # imm = 0x180
callq 0x6230
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0x4d0(%rbp)
callq 0x2c9f0
jmp 0x2c013
movq -0x4d0(%rbp), %rdi
leaq 0x19bff(%rip), %rsi     # 0x45c20
leaq 0xa48(%rip), %rdx       # 0x2ca70
callq 0x6770
jmp 0x2c112
movq -0x4d0(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
callq 0x6300
jmp 0x2c100
movq -0x490(%rbp), %rsi
leaq -0x480(%rbp), %rdi
callq 0x2cae0
jmp 0x2c064
movq -0x498(%rbp), %rdi
movslq -0x468(%rbp), %rcx
leaq -0x480(%rbp), %rsi
leaq -0x450(%rbp), %rdx
callq 0x2ca90
movl %eax, -0x4d4(%rbp)
jmp 0x2c08d
leaq -0x480(%rbp), %rdi
callq 0xa2d0
movl -0x4d4(%rbp), %eax
movl %eax, -0x46c(%rbp)
cmpl $0x1, -0x46c(%rbp)
jne 0x2c0d4
movl $0x1, -0x484(%rbp)
jmp 0x2c0ee
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
leaq -0x480(%rbp), %rdi
callq 0xa2d0
jmp 0x2c100
jmp 0x2c0d6
movl -0x1c(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x1c(%rbp)
jmp 0x2bee0
movl $0x0, -0x484(%rbp)
leaq -0x30(%rbp), %rdi
callq 0x2c970
addq $0x4e0, %rsp            # imm = 0x4E0
popq %rbp
retq
leaq -0x30(%rbp), %rdi
callq 0x2c970
movq -0x40(%rbp), %rdi
callq 0x67a0
nopw %cs:(%rax,%rax)