// File: /workspace/github_cpp_makefile_star2_O2/cybozu[P]yrmcds/cybozu/tcp.cpp
// Function: cybozu::setup_server_socket(char const*, unsigned short, bool)
int
setup_server_socket(const char* bind_addr, std::uint16_t port, bool freebind) {
    struct addrinfo hint, *res;
    std::string s_port = std::to_string(port);
    std::memset(&hint, 0, sizeof(hint));
    hint.ai_family = AF_INET6; // can accept IPv4 address
    hint.ai_socktype = SOCK_STREAM;
    hint.ai_flags = AI_PASSIVE | AI_NUMERICSERV;
    int e = getaddrinfo(bind_addr, s_port.c_str(), &hint, &res);
    if( e == EAI_FAMILY || e == EAI_ADDRFAMILY || e == EAI_NODATA ) {
      IPV4:
        logger::info() << "Binding to IPv6 fails, trying IPv4...";
        hint.ai_family = AF_INET;
        e = getaddrinfo(bind_addr, s_port.c_str(), &hint, &res);
    }
    if( e == EAI_SYSTEM ) {
        throw_unix_error(errno, "getaddrinfo");
    } else if( e != 0 ) {
        throw std::runtime_error(std::string("getaddrinfo: ") +
                                 gai_strerror(e));
    }

    int s = ::socket(res->ai_family,
                     res->ai_socktype | SOCK_NONBLOCK | SOCK_CLOEXEC,
                     res->ai_protocol);
    if( s == -1 ) {
        freeaddrinfo(res);

        // getaddrinfo may return IPv6 though the kernel disables IPv6.
        // The following is the workaround for it.
        if( hint.ai_family == AF_INET6 && errno == EAFNOSUPPORT )
            goto IPV4;

        throw_unix_error(errno, "socket");
    }

    // intentionally ignore errors
    int ok = 1;
    setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &ok, sizeof(ok));

    if( freebind ) {
        if( setsockopt(s, IPPROTO_IP, IP_FREEBIND, &ok, sizeof(ok)) == -1 ) {
            ::close(s);
            freeaddrinfo(res);
            throw_unix_error(errno, "setsockopt(IP_FREEBIND)");
        }
    }

    if( bind(s, res->ai_addr, res->ai_addrlen) == -1 ) {
        ::close(s);
        freeaddrinfo(res);
        throw_unix_error(errno, "bind");
    }
    freeaddrinfo(res);

    if( listen(s, 4096) == -1 ) {
        ::close(s);
        throw_unix_error(errno, "listen");
    }
    return s;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %rbx
subq $0xa8, %rsp
movl %edx, %ebx
movq %rdi, %r14
leaq 0x38(%rsp), %r15
movq %r15, %rdi
callq 0xd28d
xorps %xmm0, %xmm0
leaq 0x78(%rsp), %rdx
movups %xmm0, 0x8(%rdx)
movups %xmm0, 0x18(%rdx)
andq $0x0, 0x28(%rdx)
movl $0x1, 0x8(%rdx)
movabsq $0xa00000401, %rax      # imm = 0xA00000401
movq %rax, (%rdx)
movq (%r15), %rsi
leaq 0x10(%rsp), %rcx
movq %r14, %rdi
callq 0x7640
movl %eax, %ebp
addl $0x9, %eax
cmpl $0x4, %eax
ja 0x1ca8c
pushq $0x19
popq %rcx
btl %eax, %ecx
jae 0x1ca8c
leaq 0x18(%rsp), %rdi
callq 0xec96
leaq 0xbd42(%rip), %rsi      # 0x2879a
leaq 0x18(%rsp), %rdi
callq 0xf570
leaq 0x18(%rsp), %rdi
callq 0x86e4
leaq 0x78(%rsp), %rdx
movl $0x2, 0x4(%rdx)
movq 0x38(%rsp), %rsi
leaq 0x10(%rsp), %rcx
movq %r14, %rdi
callq 0x7640
movl %eax, %ebp
testl %ebp, %ebp
jne 0x1cb75
movq 0x10(%rsp), %rax
movl $0x80800, %esi          # imm = 0x80800
orl 0x8(%rax), %esi
movl 0x4(%rax), %edi
movl 0xc(%rax), %edx
callq 0x70c0
cmpl $-0x1, %eax
jne 0x1cae0
movq 0x10(%rsp), %rdi
callq 0x7680
movl 0x7c(%rsp), %ebp
callq 0x7030
cmpl $0xa, %ebp
jne 0x1cad2
cmpl $0x61, (%rax)
je 0x1ca47
movl (%rax), %edi
leaq 0xbb52(%rip), %rsi      # 0x2862d
callq 0x8513
movl %eax, %ebp
leaq 0x18(%rsp), %rcx
movl $0x1, (%rcx)
pushq $0x1
popq %rsi
pushq $0x2
popq %rdx
pushq $0x4
popq %r8
movl %eax, %edi
callq 0x79b0
testb %bl, %bl
je 0x1cb20
pushq $0xf
popq %rdx
leaq 0x18(%rsp), %rcx
pushq $0x4
popq %r8
movl %ebp, %edi
xorl %esi, %esi
callq 0x79b0
cmpl $-0x1, %eax
je 0x1cc0f
movq 0x10(%rsp), %rax
movq 0x18(%rax), %rsi
movl 0x10(%rax), %edx
movl %ebp, %edi
callq 0x7050
cmpl $-0x1, %eax
je 0x1cbef
movq 0x10(%rsp), %rdi
callq 0x7680
movl %ebp, %edi
movl $0x1000, %esi           # imm = 0x1000
callq 0x7570
cmpl $-0x1, %eax
je 0x1cbff
leaq 0x38(%rsp), %rdi
callq 0x71d0
movl %ebp, %eax
addq $0xa8, %rsp
popq %rbx
popq %r14
popq %r15
popq %rbp
retq
cmpl $-0xb, %ebp
jne 0x1cb8d
callq 0x7030
movl (%rax), %edi
leaq 0xba8b(%rip), %rsi      # 0x28613
callq 0x8513
pushq $0x10
popq %rdi
callq 0x7240
movq %rax, %rbx
leaq 0xba80(%rip), %rsi      # 0x2861f
leaq 0x58(%rsp), %rdi
leaq 0xf(%rsp), %rdx
callq 0x84d8
movl %ebp, %edi
callq 0x7750
leaq 0x18(%rsp), %rdi
leaq 0x58(%rsp), %rsi
movq %rax, %rdx
callq 0x9636
movb $0x1, %bpl
leaq 0x18(%rsp), %rsi
movq %rbx, %rdi
callq 0x78c0
xorl %ebp, %ebp
movq 0x1e410(%rip), %rsi     # 0x3aff0
movq 0x1e389(%rip), %rdx     # 0x3af70
movq %rbx, %rdi
callq 0x7950
movl %ebp, %edi
callq 0x7a90
leaq 0xbbdb(%rip), %rbx      # 0x287d8
jmp 0x1cc1d
movl %ebp, %edi
callq 0x7a90
leaq 0xbbd0(%rip), %rbx      # 0x287dd
jmp 0x1cc27
movl %ebp, %edi
callq 0x7a90
leaq 0xbba3(%rip), %rbx      # 0x287c0
movq 0x10(%rsp), %rdi
callq 0x7680
callq 0x7030
movl (%rax), %edi
movq %rbx, %rsi
callq 0x8513
jmp 0x1cc7e
movq %rax, %r14
leaq 0x18(%rsp), %rdi
callq 0x71d0
jmp 0x1cc4d
movq %rax, %r14
movb $0x1, %bpl
leaq 0x58(%rsp), %rdi
callq 0x71d0
testb %bpl, %bpl
jne 0x1cc61
jmp 0x1cc81
movq %rax, %r14
movq %rbx, %rdi
callq 0x7390
jmp 0x1cc81
movq %rax, %r14
leaq 0x18(%rsp), %rdi
callq 0x86e4
jmp 0x1cc81
jmp 0x1cc7e
jmp 0x1cc7e
movq %rax, %r14
leaq 0x38(%rsp), %rdi
callq 0x71d0
movq %r14, %rdi
callq 0x7990
nop