// File: /workspace/github_cpp_makefile_star2_O3/zeeev[P]DASVC/bamtools/src/api/internal/io/TcpSocketEngine_unix_p.cpp
// Function: BamTools::Internal::TcpSocketEngine::nativeConnect(BamTools::Internal::HostAddress const&, unsigned short)
bool TcpSocketEngine::nativeConnect(const HostAddress& address, const uint16_t port) {

    // setup connection parameters from address/port
    sockaddr_in  sockAddrIPv4;
    sockaddr_in6 sockAddrIPv6;
    sockaddr*    sockAddrPtr  = 0;
    BT_SOCKLEN_T sockAddrSize = 0;

    // IPv6
    if ( address.GetProtocol() == HostAddress::IPv6Protocol ) {

        memset(&sockAddrIPv6, 0, sizeof(sockAddrIPv6));
        sockAddrIPv6.sin6_family = AF_INET6;
        sockAddrIPv6.sin6_port   = htons(port);

        IPv6Address ip6 = address.GetIPv6Address();
        memcpy(&sockAddrIPv6.sin6_addr.s6_addr, &ip6, sizeof(ip6));

        sockAddrSize = sizeof(sockAddrIPv6);
        sockAddrPtr  = (sockaddr*)&sockAddrIPv6;
    }

    // IPv4
    else if ( address.GetProtocol() == HostAddress::IPv4Protocol ) {

        memset(&sockAddrIPv4, 0, sizeof(sockAddrIPv4));
        sockAddrIPv4.sin_family      = AF_INET;
        sockAddrIPv4.sin_port        = htons(port);
        sockAddrIPv4.sin_addr.s_addr = htonl(address.GetIPv4Address());

        sockAddrSize = sizeof(sockAddrIPv4);
        sockAddrPtr  = (sockaddr*)&sockAddrIPv4;
    }

    // unknown (should be unreachable)
    else BT_ASSERT_X(false, "TcpSocketEngine::nativeConnect() : unknown network protocol");

    // attempt connection
    int connectResult = connect(m_socketDescriptor, sockAddrPtr, sockAddrSize);

    // if failed, handle error
    if ( connectResult == -1 ) {

        // ensure state is set before checking errno
        m_socketState = TcpSocket::UnconnectedState;

        // set error type/message depending on errno
        switch ( errno ) { // <-- potential thread issues later? but can't get error type from connectResult

            case EISCONN:
                m_socketState = TcpSocket::ConnectedState; // socket was already connected
                break;
            case ECONNREFUSED:
            case EINVAL:
                m_socketError = TcpSocket::ConnectionRefusedError;
                m_errorString = "connection refused";
                break;
            case ETIMEDOUT:
                m_socketError = TcpSocket::NetworkError;
                m_errorString = "connection timed out";
                break;
            case EHOSTUNREACH:
                m_socketError = TcpSocket::NetworkError;
                m_errorString = "host unreachable";
                break;
            case ENETUNREACH:
                m_socketError = TcpSocket::NetworkError;
                m_errorString = "network unreachable";
                break;
            case EADDRINUSE:
                m_socketError = TcpSocket::SocketResourceError;
                m_errorString = "address already in use";
                break;
            case EACCES:
            case EPERM:
                m_socketError = TcpSocket::SocketAccessError;
                m_errorString = "permission denied";
                break;
            default:
                break;
        }

        // double check that we're not in 'connected' state; if so, return failure
        if ( m_socketState != TcpSocket::ConnectedState )
            return false;
    }

    // otherwise, we should be good
    // update state & return success
    m_socketState = TcpSocket::ConnectedState;
    return true;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %rbx
subq $0x28, %rsp
movl %edx, %ebp
movq %rsi, %r15
movq %rdi, %rbx
movq %rsi, %rdi
callq 0x28d60
cmpl $0x1, %eax
jne 0x50abe
xorps %xmm0, %xmm0
leaq 0xc(%rsp), %r14
movups %xmm0, 0x4(%r14)
movq $0x0, 0x14(%r14)
movw $0xa, (%r14)
rolw $0x8, %bp
movw %bp, 0x2(%r14)
movq %r15, %rdi
callq 0x28a40
movq %rax, 0x8(%r14)
movq %rdx, 0x10(%r14)
movl $0x1c, %edx
jmp 0x50b00
movq %r15, %rdi
callq 0x28d60
testl %eax, %eax
je 0x50ad1
xorl %edx, %edx
xorl %r14d, %r14d
jmp 0x50b00
leaq 0xc(%rsp), %r14
movq $0x0, 0x8(%r14)
movw $0x2, (%r14)
rolw $0x8, %bp
movw %bp, 0x2(%r14)
movq %r15, %rdi
callq 0x289b0
bswapl %eax
movl %eax, 0x4(%r14)
movl $0x10, %edx
movl (%rbx), %edi
movq %r14, %rsi
callq 0x27280
cmpl $-0x1, %eax
je 0x50b23
movl $0x1, 0x50(%rbx)
movb $0x1, %al
addq $0x28, %rsp
popq %rbx
popq %r14
popq %r15
popq %rbp
retq
movl $0x0, 0x50(%rbx)
callq 0x26110
movl (%rax), %ecx
xorl %eax, %eax
cmpl $0x61, %ecx
jg 0x50b49
cmpl $0x1, %ecx
je 0x50b82
cmpl $0xd, %ecx
je 0x50b82
cmpl $0x16, %ecx
je 0x50ba3
jmp 0x50b18
leal -0x6a(%rcx), %edx
cmpl $0x7, %edx
ja 0x50bc1
leaq 0x6788(%rip), %rcx      # 0x572e0
movslq (%rcx,%rdx,4), %rdx
addq %rcx, %rdx
jmpq *%rdx
movl $0x6, 0x4c(%rbx)
leaq 0x58(%rbx), %rdi
movq 0x60(%rbx), %rdx
leaq 0x679c(%rip), %rcx      # 0x57313
movl $0x14, %r8d
jmp 0x50c27
movl $0x3, 0x4c(%rbx)
leaq 0x58(%rbx), %rdi
movq 0x60(%rbx), %rdx
leaq 0x67cc(%rip), %rcx      # 0x57364
movl $0x11, %r8d
jmp 0x50c27
movl $0x0, 0x4c(%rbx)
leaq 0x58(%rbx), %rdi
movq 0x60(%rbx), %rdx
leaq 0x6747(%rip), %rcx      # 0x57300
movl $0x12, %r8d
jmp 0x50c27
cmpl $0x62, %ecx
je 0x50c0b
cmpl $0x65, %ecx
jne 0x50b18
movl $0x6, 0x4c(%rbx)
leaq 0x58(%rbx), %rdi
movq 0x60(%rbx), %rdx
leaq 0x6754(%rip), %rcx      # 0x57339
movl $0x13, %r8d
jmp 0x50c27
movl $0x6, 0x4c(%rbx)
leaq 0x58(%rbx), %rdi
movq 0x60(%rbx), %rdx
leaq 0x6725(%rip), %rcx      # 0x57328
movl $0x10, %r8d
jmp 0x50c27
movl $0x4, 0x4c(%rbx)
leaq 0x58(%rbx), %rdi
movq 0x60(%rbx), %rdx
leaq 0x672c(%rip), %rcx      # 0x5734d
movl $0x16, %r8d
xorl %esi, %esi
callq 0x285a0
cmpl $0x1, 0x50(%rbx)
je 0x50b0f
xorl %eax, %eax
jmp 0x50b18
nop