// File: /workspace/github_c_makefile_star2_O0/goghcrow[P]dubbo_ab/socket.c
// Function: socket_ctor
static int socket_ctor(const char *host, const char *port, bool nonblock)
{
    bool isServer = host == NULL;

    struct addrinfo hints, *servinfo, *p;
    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */

    // !!! sync for client
    int status = getaddrinfo(host, port, &hints, &servinfo);
    if (status != 0)
    {
        // gai_strerror --> getaddrinfo_strerror
        fprintf(stderr, "ERROR getaddrinfo: %s\n", gai_strerror(status));
        return -1;
    }

    int sockfd = -1;

    // 绑定到第一个能用的
    for (p = servinfo; p != NULL; p = p->ai_next)
    {
#ifdef __APPLE__
        sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
#else
        // linux 内核高版本可以直接设置 SOCK_NONBLOCK | SOCK_CLOEXEC, 节省一次fcntl系统调用
        sockfd = socket(p->ai_family, p->ai_socktype | (nonblock ? SOCK_NONBLOCK : 0) | SOCK_CLOEXEC, p->ai_protocol);
#endif

        if (sockfd == -1)
        {
            perror("ERROR socket");
            continue;
        }

#ifdef __APPLE__
        if (nonblock)
        {
            socket_setNonblock(sockfd);
        }
#endif

        int yes = 1;
        if (isServer)
        {
            if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) < 0)
            {
                perror("ERROR setsockopt SO_REUSEADDR");
                close(sockfd);
                return -1;
            }

#ifdef SO_REUSEPORT
            if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)) < 0)
            {
                perror("ERROR setsockopt SO_REUSEPORT");
                close(sockfd);
                return -1;
            }
#endif

            if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(int)) < 0)
            {

                perror("ERROR setsockopt SO_KEEPALIVE");
                close(sockfd);
                return -1;
            }
        }

        if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(int)) < 0)
        {
            perror("ERROR setsockopt TCP_NODELAY");
            close(sockfd);
            return -1;
        }

        // SO_REUSEADDR needs to be set before bind().
        // However, not all options need to be set before bind(), or even before connect().
        if (isServer && bind(sockfd, p->ai_addr, p->ai_addrlen) < 0)
        {
            perror("ERROR bind");
            continue;
        }

        break;
    }

    if (p == NULL)
    {
        // 注意bind失败要close
        fprintf(stderr, "ERROR failed to socket and bind\n");
        close(sockfd);
        return -1;
    }

    if (isServer)
    {
        // server 已经不用, client connect 仍然用
        freeaddrinfo(servinfo);
        signal(SIGPIPE, SIG_IGN);
        /*
        if (listen(sockfd, SOMAXCONN) < 0)
        {
            freeaddrinfo(servinfo);
            perror("ERROR listen");
            close(sockfd);
            return -1;
        }
        */
    }
    else
    {
        if (connect(sockfd, servinfo->ai_addr, servinfo->ai_addrlen) < 0)
        {
            perror("ERROR connect");
            freeaddrinfo(servinfo);
            close(sockfd);
            return -1;
        }
        freeaddrinfo(servinfo);
    }

    return sockfd;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x90, %rsp
movb %dl, %al
movq %rdi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
andb $0x1, %al
movb %al, -0x19(%rbp)
cmpq $0x0, -0x10(%rbp)
sete %al
andb $0x1, %al
movb %al, -0x1a(%rbp)
leaq -0x50(%rbp), %rdi
xorl %esi, %esi
movl $0x30, %edx
callq 0x2190
movl $0x0, -0x4c(%rbp)
movl $0x1, -0x48(%rbp)
movl $0x1, -0x50(%rbp)
movq -0x10(%rbp), %rdi
movq -0x18(%rbp), %rsi
leaq -0x50(%rbp), %rdx
leaq -0x58(%rbp), %rcx
callq 0x2380
movl %eax, -0x64(%rbp)
cmpl $0x0, -0x64(%rbp)
je 0x9de7
movq 0xb247(%rip), %rax      # 0x14ff8
movq (%rax), %rax
movq %rax, -0x88(%rbp)
movl -0x64(%rbp), %edi
callq 0x2140
movq -0x88(%rbp), %rdi
movq %rax, %rdx
leaq 0x5c99(%rip), %rsi      # 0xfa6d
movb $0x0, %al
callq 0x2220
movl $0xffffffff, -0x4(%rbp) # imm = 0xFFFFFFFF
jmp 0xa058
movl $0xffffffff, -0x68(%rbp) # imm = 0xFFFFFFFF
movq -0x58(%rbp), %rax
movq %rax, -0x60(%rbp)
cmpq $0x0, -0x60(%rbp)
je 0x9faf
movq -0x60(%rbp), %rax
movl 0x4(%rax), %edi
movq -0x60(%rbp), %rax
movl 0x8(%rax), %esi
movb -0x19(%rbp), %dl
xorl %eax, %eax
movl $0x800, %ecx            # imm = 0x800
testb $0x1, %dl
cmovnel %ecx, %eax
orl %eax, %esi
orl $0x80000, %esi          # imm = 0x80000
movq -0x60(%rbp), %rax
movl 0xc(%rax), %edx
callq 0x23e0
movl %eax, -0x68(%rbp)
cmpl $-0x1, -0x68(%rbp)
jne 0x9e4d
leaq 0x5be2(%rip), %rdi      # 0xfa25
callq 0x2300
jmp 0x9f9e
movl $0x1, -0x6c(%rbp)
testb $0x1, -0x1a(%rbp)
je 0x9f23
movl -0x68(%rbp), %edi
movl $0x1, %esi
movl $0x2, %edx
leaq -0x6c(%rbp), %rcx
movl $0x4, %r8d
callq 0x20a0
cmpl $0x0, %eax
jge 0x9e9f
leaq 0x5bfe(%rip), %rdi      # 0xfa84
callq 0x2300
movl -0x68(%rbp), %edi
callq 0x21a0
movl $0xffffffff, -0x4(%rbp) # imm = 0xFFFFFFFF
jmp 0xa058
movl -0x68(%rbp), %edi
movl $0x1, %esi
movl $0xf, %edx
leaq -0x6c(%rbp), %rcx
movl $0x4, %r8d
callq 0x20a0
cmpl $0x0, %eax
jge 0x9ee0
leaq 0x5bdb(%rip), %rdi      # 0xfaa2
callq 0x2300
movl -0x68(%rbp), %edi
callq 0x21a0
movl $0xffffffff, -0x4(%rbp) # imm = 0xFFFFFFFF
jmp 0xa058
movl -0x68(%rbp), %edi
movl $0x1, %esi
movl $0x9, %edx
leaq -0x6c(%rbp), %rcx
movl $0x4, %r8d
callq 0x20a0
cmpl $0x0, %eax
jge 0x9f21
leaq 0x5bb8(%rip), %rdi      # 0xfac0
callq 0x2300
movl -0x68(%rbp), %edi
callq 0x21a0
movl $0xffffffff, -0x4(%rbp) # imm = 0xFFFFFFFF
jmp 0xa058
jmp 0x9f23
movl -0x68(%rbp), %edi
movl $0x6, %esi
movl $0x1, %edx
leaq -0x6c(%rbp), %rcx
movl $0x4, %r8d
callq 0x20a0
cmpl $0x0, %eax
jge 0x9f64
leaq 0x5b93(%rip), %rdi      # 0xfade
callq 0x2300
movl -0x68(%rbp), %edi
callq 0x21a0
movl $0xffffffff, -0x4(%rbp) # imm = 0xFFFFFFFF
jmp 0xa058
testb $0x1, -0x1a(%rbp)
je 0x9f9c
movl -0x68(%rbp), %edi
movq -0x60(%rbp), %rax
movq 0x18(%rax), %rax
movq %rax, -0x78(%rbp)
movq -0x60(%rbp), %rax
movl 0x10(%rax), %edx
movq -0x78(%rbp), %rsi
callq 0x22d0
cmpl $0x0, %eax
jge 0x9f9c
leaq 0x5a47(%rip), %rdi      # 0xf9dc
callq 0x2300
jmp 0x9f9e
jmp 0x9faf
movq -0x60(%rbp), %rax
movq 0x28(%rax), %rax
movq %rax, -0x60(%rbp)
jmp 0x9df6
cmpq $0x0, -0x60(%rbp)
jne 0x9fdf
movq 0xb03b(%rip), %rax      # 0x14ff8
movq (%rax), %rdi
leaq 0x5b34(%rip), %rsi      # 0xfafb
movb $0x0, %al
callq 0x2220
movl -0x68(%rbp), %edi
callq 0x21a0
movl $0xffffffff, -0x4(%rbp) # imm = 0xFFFFFFFF
jmp 0xa058
testb $0x1, -0x1a(%rbp)
je 0x9fff
movq -0x58(%rbp), %rdi
callq 0x23d0
movl $0xd, %edi
movl $0x1, %esi
callq 0x2210
jmp 0xa052
movl -0x68(%rbp), %edi
movq -0x58(%rbp), %rax
movq 0x18(%rax), %rax
movq %rax, -0x80(%rbp)
movq -0x58(%rbp), %rax
movl 0x10(%rax), %edx
movq -0x80(%rbp), %rsi
callq 0x2370
cmpl $0x0, %eax
jge 0xa049
leaq 0x5af2(%rip), %rdi      # 0xfb1c
callq 0x2300
movq -0x58(%rbp), %rdi
callq 0x23d0
movl -0x68(%rbp), %edi
callq 0x21a0
movl $0xffffffff, -0x4(%rbp) # imm = 0xFFFFFFFF
jmp 0xa058
movq -0x58(%rbp), %rdi
callq 0x23d0
movl -0x68(%rbp), %eax
movl %eax, -0x4(%rbp)
movl -0x4(%rbp), %eax
addq $0x90, %rsp
popq %rbp
retq
nopw %cs:(%rax,%rax)