// File: 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
movq %rsp, %rbp
subq $0x120, %rsp            # imm = 0x120
movb %dl, %al
movw %si, %cx
movq %rdi, -0x8(%rbp)
movw %cx, -0xa(%rbp)
andb $0x1, %al
movb %al, -0xb(%rbp)
movzwl -0xa(%rbp), %esi
leaq -0x68(%rbp), %rdi
movq %rdi, -0xf0(%rbp)
callq 0x1baf0
movq -0xf0(%rbp), %rdi
xorps %xmm0, %xmm0
movaps %xmm0, -0x20(%rbp)
movaps %xmm0, -0x30(%rbp)
movaps %xmm0, -0x40(%rbp)
movl $0xa, -0x3c(%rbp)
movl $0x1, -0x38(%rbp)
movl $0x401, -0x40(%rbp)     # imm = 0x401
movq -0x8(%rbp), %rax
movq %rax, -0xe8(%rbp)
callq 0x8240
movq -0xe8(%rbp), %rdi
movq %rax, %rsi
leaq -0x40(%rbp), %rdx
leaq -0x48(%rbp), %rcx
callq 0x8800
movl %eax, -0xe0(%rbp)
jmp 0x5715b
movl -0xe0(%rbp), %eax
movl %eax, -0x6c(%rbp)
cmpl $-0x6, -0x6c(%rbp)
je 0x5717a
cmpl $-0x9, -0x6c(%rbp)
je 0x5717a
cmpl $-0x5, -0x6c(%rbp)
jne 0x5721e
jmp 0x5717c
leaq -0x90(%rbp), %rdi
callq 0x22390
jmp 0x5718a
leaq 0x25a1e(%rip), %rsi     # 0x7cbaf
leaq -0x90(%rbp), %rdi
callq 0x250c0
jmp 0x5719f
leaq -0x90(%rbp), %rdi
callq 0xa770
movl $0x2, -0x3c(%rbp)
movq -0x8(%rbp), %rax
movq %rax, -0x100(%rbp)
leaq -0x68(%rbp), %rdi
callq 0x8240
movq -0x100(%rbp), %rdi
movq %rax, %rsi
leaq -0x40(%rbp), %rdx
leaq -0x48(%rbp), %rcx
callq 0x8800
movl %eax, -0xf4(%rbp)
jmp 0x571e5
movl -0xf4(%rbp), %eax
movl %eax, -0x6c(%rbp)
jmp 0x5721e
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x78(%rbp)
movl %eax, -0x7c(%rbp)
jmp 0x574e8
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x78(%rbp)
movl %eax, -0x7c(%rbp)
leaq -0x90(%rbp), %rdi
callq 0xa770
jmp 0x574e8
cmpl $-0xb, -0x6c(%rbp)
jne 0x57239
callq 0x8050
movl (%rax), %edi
leaq 0x257f6(%rip), %rsi     # 0x7ca28
callq 0xa320
jmp 0x57239
cmpl $0x0, -0x6c(%rbp)
je 0x5734d
movb $0x1, -0xd2(%rbp)
movl $0x10, %edi
callq 0x82f0
movq %rax, -0x110(%rbp)
leaq -0xd1(%rbp), %rdi
movq %rdi, -0x108(%rbp)
callq 0x8bd0
movq -0x108(%rbp), %rdx
leaq 0x257b8(%rip), %rsi     # 0x7ca34
leaq -0xd0(%rbp), %rdi
callq 0xa160
jmp 0x5728a
movl -0x6c(%rbp), %edi
callq 0x8940
movq %rax, %rdx
leaq -0xb0(%rbp), %rdi
leaq -0xd0(%rbp), %rsi
callq 0xe500
jmp 0x572aa
movq -0x110(%rbp), %rdi
leaq -0xb0(%rbp), %rsi
callq 0x8ac0
jmp 0x572bf
movq -0x110(%rbp), %rdi
movb $0x0, -0xd2(%rbp)
movq 0x57d1c(%rip), %rsi     # 0xaeff0
movq 0x57c95(%rip), %rdx     # 0xaef70
callq 0x8b70
jmp 0x574fa
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x78(%rbp)
movl %eax, -0x7c(%rbp)
jmp 0x57325
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x78(%rbp)
movl %eax, -0x7c(%rbp)
jmp 0x57319
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x78(%rbp)
movl %eax, -0x7c(%rbp)
leaq -0xb0(%rbp), %rdi
callq 0x83f0
leaq -0xd0(%rbp), %rdi
callq 0x83f0
leaq -0xd1(%rbp), %rdi
callq 0x86a0
testb $0x1, -0xd2(%rbp)
jne 0x5733c
jmp 0x57348
movq -0x110(%rbp), %rdi
callq 0x8490
jmp 0x574e8
jmp 0x5734f
movq -0x48(%rbp), %rax
movl 0x4(%rax), %edi
movq -0x48(%rbp), %rax
movl 0x8(%rax), %esi
orl $0x800, %esi            # imm = 0x800
orl $0x80000, %esi          # imm = 0x80000
movq -0x48(%rbp), %rax
movl 0xc(%rax), %edx
callq 0x8130
movl %eax, -0xd8(%rbp)
cmpl $-0x1, -0xd8(%rbp)
jne 0x573b7
movq -0x48(%rbp), %rdi
callq 0x8850
cmpl $0xa, -0x3c(%rbp)
jne 0x573a2
callq 0x8050
cmpl $0x61, (%rax)
jne 0x573a2
jmp 0x5717c
callq 0x8050
movl (%rax), %edi
leaq 0x25692(%rip), %rsi     # 0x7ca42
callq 0xa320
jmp 0x573b7
movl $0x1, -0xdc(%rbp)
movl -0xd8(%rbp), %edi
movl $0x1, %esi
movl $0x2, %edx
leaq -0xdc(%rbp), %rcx
movl $0x4, %r8d
callq 0x8bf0
testb $0x1, -0xb(%rbp)
je 0x5743a
movl -0xd8(%rbp), %edi
xorl %esi, %esi
movl $0xf, %edx
leaq -0xdc(%rbp), %rcx
movl $0x4, %r8d
callq 0x8bf0
cmpl $-0x1, %eax
jne 0x57438
movl -0xd8(%rbp), %edi
callq 0x8ce0
jmp 0x5741a
movq -0x48(%rbp), %rdi
callq 0x8850
callq 0x8050
movl (%rax), %edi
leaq 0x257a4(%rip), %rsi     # 0x7cbd5
callq 0xa320
jmp 0x57438
jmp 0x5743a
movl -0xd8(%rbp), %edi
movq -0x48(%rbp), %rax
movq 0x18(%rax), %rsi
movq -0x48(%rbp), %rax
movl 0x10(%rax), %edx
callq 0x8080
cmpl $-0x1, %eax
jne 0x57484
movl -0xd8(%rbp), %edi
callq 0x8ce0
jmp 0x57466
movq -0x48(%rbp), %rdi
callq 0x8850
callq 0x8050
movl (%rax), %edi
leaq 0x25770(%rip), %rsi     # 0x7cbed
callq 0xa320
jmp 0x57484
movq -0x48(%rbp), %rdi
callq 0x8850
movl -0xd8(%rbp), %edi
movl $0x1000, %esi           # imm = 0x1000
callq 0x8710
cmpl $-0x1, %eax
jne 0x574c4
movl -0xd8(%rbp), %edi
callq 0x8ce0
jmp 0x574af
callq 0x8050
movl (%rax), %edi
leaq 0x25735(%rip), %rsi     # 0x7cbf2
callq 0xa320
jmp 0x574c4
movl -0xd8(%rbp), %eax
movl %eax, -0x114(%rbp)
leaq -0x68(%rbp), %rdi
callq 0x83f0
movl -0x114(%rbp), %eax
addq $0x120, %rsp            # imm = 0x120
popq %rbp
retq
leaq -0x68(%rbp), %rdi
callq 0x83f0
movq -0x78(%rbp), %rdi
callq 0x8bc0
nopw (%rax,%rax)