// File: /workspace/github_cpp_makefile_star2_O1/renzibei[P]TSProxy/proxyclient.cpp
// Function: readAndHandleFromServer(int, std::unordered_map<int, int, std::hash<int>, std::equal_to<int>, std::allocator<std::pair<int const, int>>>&, ClientContext*, fd_set&, int&)
int readAndHandleFromServer(int serverFd, LocalFdMap &localFdMap, ClientContext *ctx, fd_set &master_set, int& max_sd) {
    static char readBuf[constants::MAX_MSG_DATA_LENGTH];
    int tempLocalFd = 0;
    uint8_t msgType = 0;
    // ssize_t recvCode = recvReplyMsg(serverFd, (uint8_t*)readBuf, sizeof(readBuf), ctx, &tempLocalFd);
    ssize_t recvCode = recvMessage(serverFd, (uint8_t*)readBuf, sizeof(readBuf), ctx, &msgType);
    if (recvCode < 0) {
        LogHelper::log(Error, "fail to recv msg from the server");
        return recvCode;
    }
    if (msgType == SocksTrafficReplyMsg) {
        ntoh_copy4bytes(&tempLocalFd, readBuf);
        if (localFdMap.find(tempLocalFd) == localFdMap.end()) {
            LogHelper::log(Warn, "Failed to recv traffic reply, localFd :%d not in localFdMap", tempLocalFd);
            return -1;
        }
        if (localFdMap[tempLocalFd] != LocalFdPrepared) {
            LogHelper::log(Warn, "Failed to recv traffic reply, localFd status: %d, not prepared", localFdMap[tempLocalFd]);
            return -2;
        }
        ssize_t sendCode = writeNBytes(tempLocalFd, readBuf + sizeof(tempLocalFd), recvCode - sizeof(tempLocalFd), constants::clientNonBlocking);
        if (sendCode < 0) {
            LogHelper::log(Warn, "Fail to send data to localFd :%d, close it", tempLocalFd);
            close(tempLocalFd);
            FD_CLR(tempLocalFd, &master_set);
            if (tempLocalFd == max_sd) {
                while (FD_ISSET(max_sd, &master_set) == 0)
                    max_sd -= 1;
            }
            localFdMap.erase(tempLocalFd);
            return sendCode;
        }
    }
    else if (msgType == SocksTcpReplyMsg) {
        // static uint8_t socksBuffer[sizeof(SocksTcpReply)];
        // memset(socksBuffer, 0, totalLen + 1 + sizeof(localFd));
        // TODO: modify
        // int recvLen = recvMessage(serverFd, socksBuffer, sizeof(socksBuffer), ctx, 7);
        // if (recvLen < 0) {
        //     LogHelper::log(Error, "Fail to recv socks handshake forth reply from server");
        //     return recvLen;
        // }
        int recvLen = recvCode;
        if (recvLen < 2) {
            LogHelper::log(Error, "Received len less than header in socks handshake forth reply from server");
            return -3;
        }
        uint8_t respCode = readBuf[0];

        int localFd = 0;
        static uint8_t addrBuffer[constants::SocksDomainMaxLength + 2];
        memset(addrBuffer, 0, sizeof(addrBuffer));
        memcpy(addrBuffer, readBuf + 1, recvLen - 1 - sizeof(localFd));
        
        ntoh_copy4bytes(&localFd, readBuf + recvLen - sizeof(localFd));
        // if (localFd != localFd) {
        //     LogHelper::log(Error, "receive localFd not equals the localFd, server localFd:%d, localFd: %d", localFd, localFd);
        //     return -4;
        // }
        if (localFdMap.find(localFd) == localFdMap.end()) {
            LogHelper::log(Warn, "Failed in forth socks handshake from server, cannot find localFd: %d in localFdMap", localFd);
            return -4;
        }
        if (localFdMap[localFd] != LocalFdWaiting) {
            LogHelper::log(Warn, "Failed in forth socks handshake, localFd %d status is not waiting but %d", localFd, localFdMap[localFd]);
            return -5;
        }
        localFdMap[localFd] = LocalFdPrepared;
        memset(readBuf, 0, recvLen);
        readBuf[0] = constants::SocksVersion;
        readBuf[1] = respCode;
        readBuf[2] = 0x00;
        memcpy(readBuf + 3, addrBuffer, recvLen - 1 - sizeof(localFd));
        int sendCode = writeNBytes(localFd, readBuf, 3 + recvLen - 1 - sizeof(localFd), constants::clientNonBlocking);
        if (sendCode < 0) {
            LogHelper::log(Warn, "Fail in socks forth handshake, couldn't send reply to localFd: %d", localFd);
            return sendCode;
        }
        LogHelper::log(Debug, "client socks handshake end");
    }
    else {
        LogHelper::log(Warn, "Unknown msgType: %d", msgType);
        return -2;
    }
    return 0;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x18, %rsp
movq %r8, %r15
movq %rcx, %r12
movq %rdx, %rcx
movq %rsi, %r14
movl $0x0, 0xc(%rsp)
leaq 0x13(%rsp), %r8
movb $0x0, (%r8)
leaq 0x68051(%rip), %r13     # 0x6b420
movl $0xffec, %edx           # imm = 0xFFEC
movq %r13, %rsi
callq 0x2bd5
movq %rax, %rbx
testq %rax, %rax
js 0x3473
movzbl 0x13(%rsp), %edx
cmpl $0x7, %edx
je 0x3488
cmpl $0x9, %edx
jne 0x34aa
movl 0x6801b(%rip), %ecx     # 0x6b420
bswapl %ecx
movl %ecx, 0xc(%rsp)
movslq %ecx, %rax
movq (%r14), %rdi
movq 0x8(%r14), %r8
xorl %r10d, %r10d
xorl %edx, %edx
divq %r8
movq (%rdi,%rdx,8), %rax
testq %rax, %rax
je 0x3580
movq (%rax), %r9
movq %rax, %r10
cmpl 0x8(%r9), %ecx
je 0x3580
movq %rdx, %rsi
movq %r9, %r11
movq (%r9), %r9
testq %r9, %r9
je 0x357d
movslq 0x8(%r9), %rdi
movq %rdi, %rax
xorl %edx, %edx
divq %r8
movl $0x0, %r10d
cmpq %rsi, %rdx
jne 0x3580
movq %r11, %r10
cmpl %edi, %ecx
jne 0x343d
jmp 0x3580
leaq 0x427a(%rip), %rsi      # 0x76f4
xorl %edi, %edi
xorl %eax, %eax
callq 0x27f8
jmp 0x37ce
cmpq $0x1, %rbx
jg 0x34c7
leaq 0x4326(%rip), %rsi      # 0x77bb
xorl %ebp, %ebp
xorl %edi, %edi
xorl %eax, %eax
callq 0x27f8
movl $0xfffffffd, %ebx       # imm = 0xFFFFFFFD
jmp 0x37c7
leaq 0x444c(%rip), %rsi      # 0x78fd
movl $0x1, %edi
xorl %eax, %eax
callq 0x27f8
movl $0xfffffffe, %ebx       # imm = 0xFFFFFFFE
jmp 0x37ce
movb 0x67f53(%rip), %al      # 0x6b420
movb %al, 0x12(%rsp)
movl $0x0, 0x14(%rsp)
leaq 0x77f30(%rip), %r12     # 0x7b410
xorl %ebp, %ebp
movl $0x101, %edx            # imm = 0x101
movq %r12, %rdi
xorl %esi, %esi
callq 0x2130
leal -0x1(%rbx), %r15d
addq $-0x4, %r15
leaq 0x67f21(%rip), %rsi     # 0x6b421
movq %r12, %rdi
movq %r15, %rdx
callq 0x2190
movl %ebx, %r12d
movl -0x4(%r12,%r13), %ecx
bswapl %ecx
movl %ecx, 0x14(%rsp)
movslq %ecx, %rax
movq (%r14), %rdi
movq 0x8(%r14), %r8
xorl %edx, %edx
divq %r8
movq (%rdi,%rdx,8), %rax
testq %rax, %rax
je 0x36a8
movq (%rax), %r9
movq %rax, %rbp
cmpl 0x8(%r9), %ecx
je 0x36a8
movq %rdx, %rsi
movq %r9, %r10
movq (%r9), %r9
testq %r9, %r9
je 0x36a6
movslq 0x8(%r9), %rdi
movq %rdi, %rax
xorl %edx, %edx
divq %r8
movl $0x0, %ebp
cmpq %rsi, %rdx
jne 0x36a8
movq %r10, %rbp
cmpl %edi, %ecx
jne 0x3548
jmp 0x36a8
xorl %r10d, %r10d
testq %r10, %r10
je 0x366c
cmpq $0x0, (%r10)
je 0x366c
leaq 0xc(%rsp), %rsi
movq %r14, %rdi
callq 0x420e
cmpl $0x2, (%rax)
jne 0x368b
movl 0xc(%rsp), %edi
addq $-0x4, %rbx
leaq 0x67e6c(%rip), %rsi     # 0x6b424
movq %rbx, %rdx
movl $0x1, %ecx
callq 0x4b1e
movq %rax, %rbx
testq %rax, %rax
jns 0x365e
movl 0xc(%rsp), %edx
leaq 0x41b4(%rip), %rsi      # 0x7790
movl $0x1, %edi
xorl %eax, %eax
callq 0x27f8
movl 0xc(%rsp), %edi
callq 0x2380
movl 0xc(%rsp), %ecx
movq $-0x2, %rax
rolq %cl, %rax
leal 0x3f(%rcx), %edx
testl %ecx, %ecx
cmovnsl %ecx, %edx
sarl $0x6, %edx
movslq %edx, %rdx
andq %rax, (%r12,%rdx,8)
cmpl (%r15), %ecx
jne 0x3651
movl (%r15), %eax
leal 0x3f(%rax), %ecx
testl %eax, %eax
cmovnsl %eax, %ecx
sarl $0x6, %ecx
movslq %ecx, %rcx
movq (%r12,%rcx,8), %rcx
btq %rax, %rcx
jb 0x3651
movl %eax, %ecx
leal -0x1(%rcx), %eax
addl $0x3e, %ecx
testl %eax, %eax
cmovnsl %eax, %ecx
sarl $0x6, %ecx
movslq %ecx, %rcx
movq (%r12,%rcx,8), %rcx
btq %rax, %rcx
jae 0x3631
movl %eax, (%r15)
leaq 0xc(%rsp), %rsi
movq %r14, %rdi
callq 0x44e6
testq %rbx, %rbx
jns 0x37cc
jmp 0x37ce
leaq 0x40a2(%rip), %rsi      # 0x7715
movl $0x1, %edi
movl %ecx, %edx
xorl %eax, %eax
callq 0x27f8
movl $0xffffffff, %ebx       # imm = 0xFFFFFFFF
jmp 0x37ce
leaq 0xc(%rsp), %rsi
movq %r14, %rdi
callq 0x420e
movl (%rax), %edx
leaq 0x40b0(%rip), %rsi      # 0x7751
jmp 0x34b1
xorl %ebp, %ebp
testq %rbp, %rbp
je 0x3761
cmpq $0x0, (%rbp)
je 0x3761
leaq 0x14(%rsp), %rsi
movq %r14, %rdi
callq 0x420e
cmpl $0x1, (%rax)
jne 0x377f
leaq 0x14(%rsp), %r13
movq %r14, %rdi
movq %r13, %rsi
callq 0x420e
movl $0x2, (%rax)
leaq 0x67d31(%rip), %r14     # 0x6b420
movq %r14, %rdi
xorl %esi, %esi
movq %r12, %rdx
callq 0x2130
movb $0x5, 0x67d1d(%rip)     # 0x6b420
movb 0x12(%rsp), %al
movb %al, 0x67d14(%rip)      # 0x6b421
movb $0x0, 0x67d0e(%rip)     # 0x6b422
leaq 0x67d08(%rip), %rdi     # 0x6b423
leaq 0x77cee(%rip), %rsi     # 0x7b410
movq %r15, %rdx
callq 0x2190
movl (%r13), %edi
leal 0x2(%rbx), %edx
addq $-0x4, %rdx
movq %r14, %rsi
movl $0x1, %ecx
callq 0x4b1e
movq %rax, %rbx
testl %ebx, %ebx
js 0x37ae
leaq 0x4192(%rip), %rsi      # 0x78e2
movl $0x3, %edi
xorl %eax, %eax
callq 0x27f8
movb $0x1, %bpl
jmp 0x37c7
leaq 0x409c(%rip), %rsi      # 0x7804
xorl %ebp, %ebp
movl $0x1, %edi
movl %ecx, %edx
xorl %eax, %eax
callq 0x27f8
movl $0xfffffffc, %ebx       # imm = 0xFFFFFFFC
jmp 0x37c7
leaq 0x14(%rsp), %rsi
movl (%rsi), %ebx
movq %r14, %rdi
callq 0x420e
movl (%rax), %ecx
leaq 0x40c0(%rip), %rsi      # 0x7857
xorl %ebp, %ebp
movl $0x1, %edi
movl %ebx, %edx
xorl %eax, %eax
callq 0x27f8
movl $0xfffffffb, %ebx       # imm = 0xFFFFFFFB
jmp 0x37c7
movl 0x14(%rsp), %edx
leaq 0x40e7(%rip), %rsi      # 0x78a0
xorl %ebp, %ebp
movl $0x1, %edi
xorl %eax, %eax
callq 0x27f8
testb %bpl, %bpl
je 0x37ce
xorl %ebx, %ebx
movl %ebx, %eax
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq