// File: nvanbenschoten[P]byzantine-agreement/src/udp_conn.cc
// Function: udp::Client::SendWithAck(char const*, unsigned long, unsigned int, std::function<udp::ServerAction (std::shared_ptr<udp::Client const>, char*, unsigned long)>) const
void Client::SendWithAck(const char *buf, size_t size, unsigned int attempts,
                         OnReceiveFn validAck) const {
  bool noLimit = attempts == 0;
  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()) {
        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 $0x4a0, %rsp            # imm = 0x4A0
movq %r8, -0x478(%rbp)
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movl %ecx, -0x1c(%rbp)
movq %r8, -0x28(%rbp)
movq -0x8(%rbp), %rax
movq %rax, -0x470(%rbp)
cmpl $0x0, -0x1c(%rbp)
sete %al
andb $0x1, %al
movb %al, -0x29(%rbp)
movb $0x1, %al
testb $0x1, -0x29(%rbp)
movb %al, -0x479(%rbp)
jne 0x22c77
cmpl $0x0, -0x1c(%rbp)
seta %al
movb %al, -0x479(%rbp)
movb -0x479(%rbp), %al
testb $0x1, %al
jne 0x22c86
jmp 0x22df2
movq -0x470(%rbp), %rdi
movq -0x10(%rbp), %rsi
movq -0x18(%rbp), %rdx
callq 0x22b60
leaq -0x430(%rbp), %rdi
xorl %esi, %esi
movl $0x400, %edx            # imm = 0x400
callq 0x6270
movq -0x470(%rbp), %rax
movl $0x10, -0x444(%rbp)
movl 0x10(%rax), %edi
leaq -0x430(%rbp), %rsi
movl $0x400, %edx            # imm = 0x400
xorl %ecx, %ecx
leaq -0x440(%rbp), %r8
leaq -0x444(%rbp), %r9
callq 0x6330
movl %eax, -0x448(%rbp)
cmpl $0x0, -0x448(%rbp)
jge 0x22d5c
callq 0x23450
testb $0x1, %al
jne 0x22cfc
jmp 0x22d01
jmp 0x22de4
movl $0x180, %edi            # imm = 0x180
callq 0x6240
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0x488(%rbp)
callq 0x234a0
jmp 0x22d1f
movq -0x488(%rbp), %rdi
leaq 0x2fcf3(%rip), %rsi     # 0x52a20
leaq 0x7ec(%rip), %rdx       # 0x23520
callq 0x6730
movq -0x488(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x450(%rbp)
movl %eax, -0x454(%rbp)
callq 0x6300
jmp 0x22dfb
movq -0x470(%rbp), %rsi
leaq -0x468(%rbp), %rdi
movq %rdi, -0x498(%rbp)
callq 0x23590
movq -0x478(%rbp), %rdi
movq -0x498(%rbp), %rsi
movslq -0x448(%rbp), %rcx
leaq -0x430(%rbp), %rdx
callq 0x23540
movl %eax, -0x48c(%rbp)
jmp 0x22d9f
leaq -0x468(%rbp), %rdi
callq 0x21160
movl -0x48c(%rbp), %eax
movl %eax, -0x458(%rbp)
cmpl $0x1, -0x458(%rbp)
jne 0x22de2
jmp 0x22df2
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x450(%rbp)
movl %eax, -0x454(%rbp)
leaq -0x468(%rbp), %rdi
callq 0x21160
jmp 0x22dfb
jmp 0x22de4
movl -0x1c(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x1c(%rbp)
jmp 0x22c5c
addq $0x4a0, %rsp            # imm = 0x4A0
popq %rbp
retq
movq -0x450(%rbp), %rdi
callq 0x6750
nopw (%rax,%rax)