// File: /workspace/github_cpp_makefile_star2_O2/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, %rbx
leaq 0x13(%rsp), %r8
movb $0x0, (%r8)
leaq 0x6823b(%rip), %r13     # 0x6b430
movl $0xffec, %edx           # imm = 0xFFEC
movq %r13, %rsi
callq 0x2ac7
movq %rax, %r14
testq %rax, %rax
js 0x32de
movzbl 0x13(%rsp), %edx
cmpl $0x7, %edx
je 0x32f6
cmpl $0x9, %edx
jne 0x3313
movl 0x68205(%rip), %eax     # 0x6b430
bswapl %eax
leaq 0xc(%rsp), %rsi
movl %eax, (%rsi)
movq %rbx, %rdi
callq 0x40ca
testq %rax, %rax
je 0x3419
leaq 0xc(%rsp), %rsi
movq %rbx, %rdi
callq 0x3d66
cmpl $0x2, (%rax)
jne 0x3432
movl 0xc(%rsp), %edi
addq $-0x4, %r14
leaq 0x681ca(%rip), %rsi     # 0x6b434
pushq $0x1
popq %rcx
movq %r14, %rdx
callq 0x46b8
xorl %ebp, %ebp
testq %rax, %rax
jns 0x3455
movq %rax, %r14
movl 0xc(%rsp), %edx
leaq 0x3502(%rip), %rsi      # 0x6790
pushq $0x1
popq %rdi
xorl %eax, %eax
callq 0x26e8
movl 0xc(%rsp), %edi
callq 0x2390
movl 0xc(%rsp), %ecx
pushq $-0x2
popq %rdi
rolq %cl, %rdi
pushq $0x40
popq %rsi
movl %ecx, %eax
cltd
idivl %esi
cltq
andq %rdi, (%r12,%rax,8)
cmpl (%r15), %ecx
jne 0x34a7
movl %ecx, %eax
cltd
idivl %esi
cltq
movq (%r12,%rax,8), %rax
btq %rdx, %rax
jb 0x34a7
decl %ecx
movl %ecx, (%r15)
jmp 0x32c2
leaq 0x340f(%rip), %rsi      # 0x66f4
xorl %edi, %edi
xorl %eax, %eax
callq 0x26e8
movl %r14d, %ebp
jmp 0x3455
cmpq $0x1, %r14
ja 0x331f
leaq 0x34b8(%rip), %rsi      # 0x67bb
xorl %edi, %edi
xorl %eax, %eax
callq 0x26e8
pushq $-0x3
jmp 0x3454
leaq 0x35e3(%rip), %rsi      # 0x68fd
jmp 0x3448
movb 0x6810a(%rip), %bpl     # 0x6b430
leaq 0x780f3(%rip), %r12     # 0x7b420
movl $0x101, %edx            # imm = 0x101
movq %r12, %rdi
xorl %esi, %esi
callq 0x2140
leal -0x1(%r14), %r15d
addq $-0x4, %r15
leaq 0x680e6(%rip), %rsi     # 0x6b431
movq %r12, %rdi
movq %r15, %rdx
callq 0x21a0
movl -0x4(%r14,%r13), %eax
bswapl %eax
leaq 0x14(%rsp), %rsi
movl %eax, (%rsi)
movq %rbx, %rdi
callq 0x40ca
testq %rax, %rax
je 0x3466
leaq 0x14(%rsp), %rsi
movq %rbx, %rdi
callq 0x3d66
cmpl $0x1, (%rax)
jne 0x347f
leaq 0x14(%rsp), %r12
movq %rbx, %rdi
movq %r12, %rsi
callq 0x3d66
movl $0x2, (%rax)
leaq 0x68088(%rip), %rbx     # 0x6b430
movl %ebp, %r13d
xorl %ebp, %ebp
movq %rbx, %rdi
xorl %esi, %esi
movq %r14, %rdx
callq 0x2140
movb $0x5, 0x6806f(%rip)     # 0x6b430
movb %r13b, 0x68069(%rip)    # 0x6b431
movb $0x0, 0x68063(%rip)     # 0x6b432
leaq 0x6805d(%rip), %rdi     # 0x6b433
leaq 0x78043(%rip), %rsi     # 0x7b420
movq %r15, %rdx
callq 0x21a0
movl (%r12), %edi
addq $-0x2, %r14
pushq $0x1
popq %rcx
movq %rbx, %rsi
movq %r14, %rdx
callq 0x46b8
movq %rax, %rbx
testl %ebx, %ebx
js 0x34b9
leaq 0x34d5(%rip), %rsi      # 0x68e2
pushq $0x3
popq %rdi
xorl %eax, %eax
callq 0x26e8
jmp 0x3455
movl 0xc(%rsp), %edx
leaq 0x32f1(%rip), %rsi      # 0x6715
pushq $0x1
popq %rdi
xorl %eax, %eax
callq 0x26e8
pushq $-0x1
jmp 0x3454
leaq 0xc(%rsp), %rsi
movq %rbx, %rdi
callq 0x3d66
movl (%rax), %edx
leaq 0x3309(%rip), %rsi      # 0x6751
pushq $0x1
popq %rdi
xorl %eax, %eax
callq 0x26e8
pushq $-0x2
popq %rbp
movl %ebp, %eax
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movl 0x14(%rsp), %edx
leaq 0x3393(%rip), %rsi      # 0x6804
pushq $0x1
popq %rdi
xorl %eax, %eax
callq 0x26e8
pushq $-0x4
jmp 0x3454
leaq 0x14(%rsp), %rsi
movl (%rsi), %ebp
movq %rbx, %rdi
callq 0x3d66
movl (%rax), %ecx
leaq 0x33c0(%rip), %rsi      # 0x6857
pushq $0x1
popq %rdi
movl %ebp, %edx
xorl %eax, %eax
callq 0x26e8
pushq $-0x5
jmp 0x3454
leaq 0xc(%rsp), %rsi
movq %rbx, %rdi
callq 0x40e8
jmp 0x32ee
movl 0x14(%rsp), %edx
leaq 0x33dc(%rip), %rsi      # 0x68a0
pushq $0x1
popq %rdi
xorl %eax, %eax
callq 0x26e8
movl %ebx, %ebp
jmp 0x3455