// File: nvanbenschoten[P]total-order-multicast/src/udp_conn.cc
// Function: udp::Server::Listen(std::function<udp::ServerAction (std::shared_ptr<udp::Client>, char*, unsigned long)>, std::function<udp::ServerAction ()>) const
void Server::Listen(OnReceiveFn rcv, OnTimeout timeout) const {
  // While the server is running, wait for datagrams and
  // call the provided closure with their data.
  while (1) {
    // Create a zeroed out buffer to read the message into.
    char buf[BUFSIZE];
    bzero(buf, BUFSIZE);

    // Receive from the socket.
    struct sockaddr_in clientaddr;
    socklen_t clientlen = sizeof(clientaddr);
    int n = recvfrom(sockfd_, buf, BUFSIZE, 0, (struct sockaddr *)&clientaddr,
                     &clientlen);
    if (n < 0) {
      if (IsErrnoTimeout() && timeout != nullptr) {
        auto action = timeout();
        switch (action) {
          case ServerAction::Continue:
            continue;
          case ServerAction::Stop:
            return;
          default:
            throw std::invalid_argument("unexpected ServerAction value");
        }
      } else {
        throw net::ReceiveException();
      }
    }

    // Call closure with new client.
    auto client = std::make_shared<udp::Client>(clientaddr);

    // Call the receive callback with the data received.
    auto action = rcv(client, buf, n);
    if (action == ServerAction::Stop) {
      return;
    }
  }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x4d0, %rsp            # imm = 0x4D0
movq %rsi, -0x498(%rbp)
movq %rdx, -0x490(%rbp)
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movq -0x8(%rbp), %rax
movq %rax, -0x488(%rbp)
leaq -0x420(%rbp), %rdi
xorl %esi, %esi
movl $0x400, %edx            # imm = 0x400
callq 0x6260
movq -0x488(%rbp), %rax
movl $0x10, -0x434(%rbp)
movl (%rax), %edi
leaq -0x420(%rbp), %rsi
movl $0x400, %edx            # imm = 0x400
xorl %ecx, %ecx
leaq -0x430(%rbp), %r8
leaq -0x434(%rbp), %r9
callq 0x6340
movl %eax, -0x438(%rbp)
cmpl $0x0, -0x438(%rbp)
jge 0x2c4a9
callq 0x2c9a0
testb $0x1, %al
jne 0x2c398
jmp 0x2c44e
movq -0x490(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x2cc80
testb $0x1, %al
jne 0x2c3b1
jmp 0x2c44e
movq -0x490(%rbp), %rdi
callq 0x2ccb0
movl %eax, -0x43c(%rbp)
movl -0x43c(%rbp), %eax
movl %eax, -0x49c(%rbp)
testl %eax, %eax
je 0x2c3e2
jmp 0x2c3d5
movl -0x49c(%rbp), %eax
subl $0x1, %eax
je 0x2c3e7
jmp 0x2c3ec
jmp 0x2c330
jmp 0x2c588
movl $0x10, %edi
callq 0x6230
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0x4a8(%rbp)
leaq 0x3d4c(%rip), %rsi      # 0x30156
callq 0x6840
jmp 0x2c411
movq -0x4a8(%rbp), %rdi
movq 0x19ba9(%rip), %rsi     # 0x45fc8
movq 0x19b8a(%rip), %rdx     # 0x45fb0
callq 0x6770
movq -0x4a8(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x448(%rbp)
movl %eax, -0x44c(%rbp)
callq 0x6300
jmp 0x2c591
movl $0x180, %edi            # imm = 0x180
callq 0x6230
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0x4b0(%rbp)
callq 0x2c9f0
jmp 0x2c46c
movq -0x4b0(%rbp), %rdi
leaq 0x197a6(%rip), %rsi     # 0x45c20
leaq 0x5ef(%rip), %rdx       # 0x2ca70
callq 0x6770
movq -0x4b0(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x448(%rbp)
movl %eax, -0x44c(%rbp)
callq 0x6300
jmp 0x2c591
leaq -0x460(%rbp), %rdi
movq %rdi, -0x4c8(%rbp)
leaq -0x430(%rbp), %rsi
callq 0x2ccf0
movq -0x4c8(%rbp), %rsi
leaq -0x478(%rbp), %rdi
movq %rdi, -0x4c0(%rbp)
callq 0xaf40
movq -0x498(%rbp), %rdi
movq -0x4c0(%rbp), %rsi
movslq -0x438(%rbp), %rcx
leaq -0x420(%rbp), %rdx
callq 0x2ca90
movl %eax, -0x4b4(%rbp)
jmp 0x2c506
leaq -0x478(%rbp), %rdi
callq 0xa2d0
movl -0x4b4(%rbp), %eax
movl %eax, -0x464(%rbp)
cmpl $0x1, -0x464(%rbp)
jne 0x2c55f
movl $0x1, -0x47c(%rbp)
jmp 0x2c569
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x448(%rbp)
movl %eax, -0x44c(%rbp)
leaq -0x478(%rbp), %rdi
callq 0xa2d0
leaq -0x460(%rbp), %rdi
callq 0xa2d0
jmp 0x2c591
movl $0x0, -0x47c(%rbp)
leaq -0x460(%rbp), %rdi
callq 0xa2d0
movl -0x47c(%rbp), %eax
testl %eax, %eax
je 0x2c583
jmp 0x2c581
jmp 0x2c588
jmp 0x2c330
addq $0x4d0, %rsp            # imm = 0x4D0
popq %rbp
retq
movq -0x448(%rbp), %rdi
callq 0x67a0
nopl (%rax)