// File: 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:
subq $0x78, %rsp
movw %dx, %ax
movq %rdi, 0x68(%rsp)
movq %rsi, 0x60(%rsp)
movw %ax, 0x5e(%rsp)
movq 0x68(%rsp), %rax
movq %rax, 0x8(%rsp)
movq $0x0, 0x28(%rsp)
movl $0x0, 0x24(%rsp)
movq 0x60(%rsp), %rdi
callq 0x7ba20
cmpl $0x1, %eax
jne 0xe18c3
leaq 0x30(%rsp), %rdi
xorl %esi, %esi
movl $0x1c, %edx
callq 0x73d00
movw $0xa, 0x30(%rsp)
movzwl 0x5e(%rsp), %edi
callq 0x71380
movw %ax, 0x32(%rsp)
movq 0x60(%rsp), %rdi
callq 0x7b060
movq %rax, 0x14(%rsp)
movq %rdx, 0x1c(%rsp)
movq 0x14(%rsp), %rax
movq %rax, 0x38(%rsp)
movq 0x1c(%rsp), %rax
movq %rax, 0x40(%rsp)
movl $0x1c, 0x24(%rsp)
leaq 0x30(%rsp), %rax
movq %rax, 0x28(%rsp)
jmp 0xe1929
movq 0x60(%rsp), %rdi
callq 0x7ba20
cmpl $0x0, %eax
jne 0xe1922
leaq 0x4c(%rsp), %rdi
xorl %esi, %esi
movl $0x10, %edx
callq 0x73d00
movw $0x2, 0x4c(%rsp)
movzwl 0x5e(%rsp), %edi
callq 0x71380
movw %ax, 0x4e(%rsp)
movq 0x60(%rsp), %rdi
callq 0x7aef0
movl %eax, %edi
callq 0x75020
movl %eax, 0x50(%rsp)
movl $0x10, 0x24(%rsp)
leaq 0x4c(%rsp), %rax
movq %rax, 0x28(%rsp)
jmp 0xe1927
callq 0x761a0
jmp 0xe1929
movq 0x8(%rsp), %rax
movl (%rax), %edi
movq 0x28(%rsp), %rsi
movl 0x24(%rsp), %edx
callq 0x75850
movl %eax, 0x10(%rsp)
cmpl $-0x1, 0x10(%rsp)
jne 0xe1ab4
movq 0x8(%rsp), %rax
movl $0x0, 0x50(%rax)
callq 0x712b0
movl (%rax), %eax
movl %eax, 0x4(%rsp)
subl $0x1, %eax
je 0xe1a80
jmp 0xe196f
movl 0x4(%rsp), %eax
subl $0xd, %eax
je 0xe1a80
jmp 0xe197e
movl 0x4(%rsp), %eax
subl $0x16, %eax
je 0xe19e7
jmp 0xe1989
movl 0x4(%rsp), %eax
subl $0x62, %eax
je 0xe1a62
jmp 0xe1998
movl 0x4(%rsp), %eax
subl $0x65, %eax
je 0xe1a44
jmp 0xe19a7
movl 0x4(%rsp), %eax
subl $0x6a, %eax
je 0xe19d6
jmp 0xe19b2
movl 0x4(%rsp), %eax
subl $0x6e, %eax
je 0xe1a08
jmp 0xe19bd
movl 0x4(%rsp), %eax
subl $0x6f, %eax
je 0xe19e7
jmp 0xe19c8
movl 0x4(%rsp), %eax
subl $0x71, %eax
je 0xe1a26
jmp 0xe1a9e
movq 0x8(%rsp), %rax
movl $0x1, 0x50(%rax)
jmp 0xe1aa0
movq 0x8(%rsp), %rdi
movl $0x0, 0x4c(%rdi)
addq $0x58, %rdi
leaq 0xab6f(%rip), %rsi      # 0xec56d
callq 0x78d10
jmp 0xe1aa0
movq 0x8(%rsp), %rdi
movl $0x6, 0x4c(%rdi)
addq $0x58, %rdi
leaq 0xab61(%rip), %rsi      # 0xec580
callq 0x78d10
jmp 0xe1aa0
movq 0x8(%rsp), %rdi
movl $0x6, 0x4c(%rdi)
addq $0x58, %rdi
leaq 0xab58(%rip), %rsi      # 0xec595
callq 0x78d10
jmp 0xe1aa0
movq 0x8(%rsp), %rdi
movl $0x6, 0x4c(%rdi)
addq $0x58, %rdi
leaq 0xab4b(%rip), %rsi      # 0xec5a6
callq 0x78d10
jmp 0xe1aa0
movq 0x8(%rsp), %rdi
movl $0x4, 0x4c(%rdi)
addq $0x58, %rdi
leaq 0xab41(%rip), %rsi      # 0xec5ba
callq 0x78d10
jmp 0xe1aa0
movq 0x8(%rsp), %rdi
movl $0x3, 0x4c(%rdi)
addq $0x58, %rdi
leaq 0xab3a(%rip), %rsi      # 0xec5d1
callq 0x78d10
jmp 0xe1aa0
jmp 0xe1aa0
movq 0x8(%rsp), %rax
cmpl $0x1, 0x50(%rax)
je 0xe1ab2
movb $0x0, 0x77(%rsp)
jmp 0xe1ac5
jmp 0xe1ab4
movq 0x8(%rsp), %rax
movl $0x1, 0x50(%rax)
movb $0x1, 0x77(%rsp)
movb 0x77(%rsp), %al
andb $0x1, %al
addq $0x78, %rsp
retq