// File: /workspace/github_cpp_makefile_star2_O3/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 0x67068(%rip), %r13     # 0x6a420
movl $0xffec, %edx           # imm = 0xFFEC
movq %r13, %rsi
callq 0x2bd6
movq %rax, %r14
testq %rax, %rax
js 0x34bb
movzbl 0x13(%rsp), %edx
cmpl $0x7, %edx
je 0x34d3
cmpl $0x9, %edx
jne 0x34f3
movl 0x67032(%rip), %eax     # 0x6a420
bswapl %eax
leaq 0xc(%rsp), %rsi
movl %eax, (%rsi)
movq %rbx, %rdi
callq 0x42fe
testq %rax, %rax
je 0x35fd
leaq 0xc(%rsp), %rsi
movq %rbx, %rdi
callq 0x405a
cmpl $0x2, (%rax)
jne 0x361b
movl 0xc(%rsp), %edi
addq $-0x4, %r14
leaq 0x66ff7(%rip), %rsi     # 0x6a424
movq %r14, %rdx
movl $0x1, %ecx
callq 0x494f
xorl %ebp, %ebp
testq %rax, %rax
jns 0x3642
movq %rax, %r14
movl 0xc(%rsp), %edx
leaq 0x333d(%rip), %rsi      # 0x6790
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 0x34ac
movl %ecx, %eax
leal -0x1(%rax), %ecx
addl $0x3e, %eax
testl %ecx, %ecx
cmovnsl %ecx, %eax
sarl $0x6, %eax
cltq
movq (%r12,%rax,8), %rax
btq %rcx, %rax
jae 0x348d
movl %ecx, (%r15)
leaq 0xc(%rsp), %rsi
movq %rbx, %rdi
callq 0x435a
jmp 0x34cb
leaq 0x3232(%rip), %rsi      # 0x66f4
xorl %edi, %edi
xorl %eax, %eax
callq 0x27f8
movl %r14d, %ebp
jmp 0x3642
cmpq $0x1, %r14
ja 0x34ff
leaq 0x32db(%rip), %rsi      # 0x67bb
xorl %edi, %edi
xorl %eax, %eax
callq 0x27f8
movl $0xfffffffd, %ebp       # imm = 0xFFFFFFFD
jmp 0x3642
leaq 0x3403(%rip), %rsi      # 0x68fd
jmp 0x3631
movb 0x66f1a(%rip), %bpl     # 0x6a420
leaq 0x76f03(%rip), %r12     # 0x7a410
movl $0x101, %edx            # imm = 0x101
movq %r12, %rdi
xorl %esi, %esi
callq 0x2130
leal -0x1(%r14), %r15d
addq $-0x4, %r15
leaq 0x66ef6(%rip), %rsi     # 0x6a421
movq %r12, %rdi
movq %r15, %rdx
callq 0x2190
movl -0x4(%r14,%r13), %eax
bswapl %eax
leaq 0x14(%rsp), %rsi
movl %eax, (%rsi)
movq %rbx, %rdi
callq 0x42fe
testq %rax, %rax
je 0x3653
leaq 0x14(%rsp), %rsi
movq %rbx, %rdi
callq 0x405a
cmpl $0x1, (%rax)
jne 0x3671
leaq 0x14(%rsp), %r12
movq %rbx, %rdi
movq %r12, %rsi
callq 0x405a
movl $0x2, (%rax)
leaq 0x66e98(%rip), %rbx     # 0x6a420
movl %ebp, %r13d
xorl %ebp, %ebp
movq %rbx, %rdi
xorl %esi, %esi
movq %r14, %rdx
callq 0x2130
movb $0x5, 0x66e7f(%rip)     # 0x6a420
movb %r13b, 0x66e79(%rip)    # 0x6a421
movb $0x0, 0x66e73(%rip)     # 0x6a422
leaq 0x66e6d(%rip), %rdi     # 0x6a423
leaq 0x76e53(%rip), %rsi     # 0x7a410
movq %r15, %rdx
callq 0x2190
movl (%r12), %edi
addq $-0x2, %r14
movq %rbx, %rsi
movq %r14, %rdx
movl $0x1, %ecx
callq 0x494f
movq %rax, %rbx
testl %ebx, %ebx
js 0x369e
leaq 0x32f3(%rip), %rsi      # 0x68e2
movl $0x3, %edi
xorl %eax, %eax
callq 0x27f8
jmp 0x3642
movl 0xc(%rsp), %edx
leaq 0x310d(%rip), %rsi      # 0x6715
movl $0x1, %edi
xorl %eax, %eax
callq 0x27f8
movl $0xffffffff, %ebp       # imm = 0xFFFFFFFF
jmp 0x3642
leaq 0xc(%rsp), %rsi
movq %rbx, %rdi
callq 0x405a
movl (%rax), %edx
leaq 0x3120(%rip), %rsi      # 0x6751
movl $0x1, %edi
xorl %eax, %eax
callq 0x27f8
movl $0xfffffffe, %ebp       # imm = 0xFFFFFFFE
movl %ebp, %eax
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movl 0x14(%rsp), %edx
leaq 0x31a6(%rip), %rsi      # 0x6804
movl $0x1, %edi
xorl %eax, %eax
callq 0x27f8
movl $0xfffffffc, %ebp       # imm = 0xFFFFFFFC
jmp 0x3642
leaq 0x14(%rsp), %rsi
movl (%rsi), %ebp
movq %rbx, %rdi
callq 0x405a
movl (%rax), %ecx
leaq 0x31ce(%rip), %rsi      # 0x6857
movl $0x1, %edi
movl %ebp, %edx
xorl %eax, %eax
callq 0x27f8
movl $0xfffffffb, %ebp       # imm = 0xFFFFFFFB
jmp 0x3642
movl 0x14(%rsp), %edx
leaq 0x31f7(%rip), %rsi      # 0x68a0
movl $0x1, %edi
xorl %eax, %eax
callq 0x27f8
movl %ebx, %ebp
jmp 0x3642