// File: /workspace/github_cpp_makefile_star2_O2/renzibei[P]TSProxy/proxyserver.cpp
// Function: recvAndHandleClientData(int, std::unordered_map<int, ClientNode*, std::hash<int>, std::equal_to<int>, std::allocator<std::pair<int const, ClientNode*>>>&, std::unordered_map<int, HostNode, std::hash<int>, std::equal_to<int>, std::allocator<std::pair<int const, HostNode>>>&, fd_set&, fd_set&, int&, int&, int&)
int recvAndHandleClientData(int sockFd, ClientMap &cMap, HostMap &h2lMap, fd_set &readFdSet, fd_set &writeFdSet, int &max_read_sd, int &max_write_sd, int &max_all_sd) {
    static uint8_t buf[constants::MAX_MSG_DATA_LENGTH];
    memset(buf, 0, sizeof(buf));
    uint8_t msgType = 0;
    int recvLen = recvData(sockFd, buf, sizeof(buf), cMap, &msgType);
    if (recvLen < 0) {
        LogHelper::log(Error, "Failed to recv data from client: %d", sockFd);
        return recvLen;
    }
    LogHelper::log(Debug, "Has recv a msg from client: %d, goning to handleit", sockFd);
    using namespace constants;
    SocketMap *l2hMap = &(cMap[sockFd]->sMap);
    if (msgType == constants::SocksTcpRequestMsg) {
        LogHelper::log(Debug, "it's a tcp request msg");
        static char dstAddrBuf[SocksDomainMaxLength];
        memset(dstAddrBuf, 0, sizeof(dstAddrBuf));
        uint8_t respCode = 0x00;
        uint8_t requestCmd = buf[0], dstAddrType = buf[1];
        int localFd = -1;
        if (requestCmd == SocksConnectCmd) {
            uint16_t dstPort = 0;
            if (dstAddrType == SocksAddrIpv4Type) {
                if (recvLen < 2 + 4 + 2 + 4) {
                    LogHelper::log(Warn, "len less than ipv4 addr, recvLen: %d", recvLen);
                    respCode = 0xff;
                }
                else {
                    if (inet_ntop(AF_INET, buf + 2, dstAddrBuf, sizeof(dstAddrBuf)) == NULL) {
                        LogHelper::log(Warn, "Fail to convert ipv4 num to str, %s", strerror(errno));
                        respCode = 0xff;
                    }
                    else {
                        ntoh_copy2bytes(&dstPort, buf + 6);
                        ntoh_copy4bytes(&localFd, buf + 8);
                    }
                }
            }
            else if (dstAddrType == SocksAddrIpv6Type) {
                if (recvLen < 2 + 16 + 2 + 4) {
                    LogHelper::log(Warn, "len less than ipv6 addr, recvLen: %d", recvLen);
                    respCode = 0xff;
                }
                else {
                    if (inet_ntop(AF_INET6, buf + 2, dstAddrBuf, sizeof(dstAddrBuf)) == NULL) {
                        LogHelper::log(Warn, "Fail to convert ipv6 num to str, %s", strerror(errno));
                        respCode = 0xff;
                    }
                    else {
                        ntoh_copy2bytes(&dstPort, buf + 18);
                        ntoh_copy4bytes(&localFd, buf + 20);
                    }
                }
            }
            else if (dstAddrType == SocksAddrDomainType) {
                if (recvLen < 2 + 1) {
                    LogHelper::log(Warn, "len less than domain header, recvLen: %d", recvLen);
                    respCode = 0xff;
                }
                else {
                    uint8_t domainAddrLen = buf[2];
                    if (recvLen < 2 + 1 + domainAddrLen + 2 + 4) {
                        LogHelper::log(Warn, "len less than domain addr, recvLen: %d", recvLen);
                        respCode = 0xff;
                    }
                    else {
                        memcpy(dstAddrBuf, buf + 3, domainAddrLen);
                        ntoh_copy2bytes(&dstPort, buf + 3 + domainAddrLen);
                        ntoh_copy4bytes(&localFd, buf + 3 + domainAddrLen + 2);
                    }
                }
            }
            else {
                LogHelper::log(Warn, "Unknown addrtype, type: %d", dstAddrType);
                respCode = 0xff;
            }

            if (respCode == 0x00) {
                
                LogHelper::log(Debug, "begin to try to connect socket to host");
                
                int hostSd = tryConnectSocket(dstAddrBuf, dstPort, constants::serverNonBlocking);
                LogHelper::log(Debug, "try end");
                if (hostSd < 0) {
                    respCode = 0xff;
                }
                else {
                    time_t nowT = time(NULL);
                    (*l2hMap)[localFd] = SocketNode(hostSd, nowT);
                    h2lMap[hostSd] = HostNode(sockFd, localFd, nowT);
                    FD_SET(hostSd, &readFdSet);
                    if (hostSd > max_read_sd) {
                        max_read_sd = hostSd;
                    }
                    FD_SET(hostSd, &writeFdSet);
                    if (hostSd > max_write_sd) {
                        max_write_sd = hostSd;
                    }
                    max_all_sd = std::max(max_read_sd, max_write_sd);
                    LogHelper::log(Debug, "Add hostFd :%d", hostSd);

                }
            }


        }
        else {
            respCode = 0xff;
        }

        

        static uint8_t replyMsgBuf[MAX_MSG_DATA_LENGTH];
        memset(replyMsgBuf, 0, sizeof(replyMsgBuf));
        replyMsgBuf[0] = respCode;
        replyMsgBuf[1] = SocksAddrIpv4Type;
        memset(replyMsgBuf + 2, 0, 4);
        uint16_t fakePort = 1728;
        hton_copy2bytes(replyMsgBuf + 6 , &fakePort);
        hton_copy4bytes(replyMsgBuf + 6 + sizeof(fakePort), &localFd);
        size_t replyLen = 1 + 1 + 4 + sizeof(fakePort) + sizeof(localFd);
        int sendCode = sendData(sockFd, replyMsgBuf, replyLen, cMap, SocksTcpReplyMsg);
        if (sendCode < 0) {
            LogHelper::log(Error, "Failed to send socks forth handshake reply from server");
            return sendCode;
        }
        
        
    }
    else if (msgType == SocksTrafficRequestMsg) {
        LogHelper::log(Debug, "it's a traffic request msg");

        int localFd = -1;
        if (recvLen < sizeof(localFd)) {
            LogHelper::log(Error, "Fail to receive socks traffic request, length less than localFd");
            return -5;
        }
        ntoh_copy4bytes(&localFd, buf);
        auto l2hIt = l2hMap->find(localFd);
        if (l2hIt == l2hMap->end()) {
            LogHelper::log(Warn, "Can not find localFd %d in l2hMap", localFd);
            return 0;
        }
        int hostSd = (*l2hMap)[localFd].sockFd;
        h2lMap[hostSd].writeToBuffer(buf + sizeof(localFd), recvLen - sizeof(localFd));
        // ssize_t sendCode = writeNBytes(hostSd, buf + sizeof(localFd), recvLen - sizeof(localFd), constants::serverNonBlocking);
        // if (sendCode < 0) {
        //     LogHelper::log(Warn, "Failed to send data to host, localFd: %d, will close hostSd", localFd);
        //     close(hostSd);
        //     FD_CLR(hostSd, &readFdSet);
        //     if (hostSd == max_read_sd) {
        //         while (FD_ISSET(max_read_sd, &readFdSet) == 0)
        //             max_read_sd -= 1;
        //     }
        //     l2hMap->erase(localFd);
        //     h2lMap.erase(hostSd);
        //     return -7;
        // }
        LogHelper::log(Debug, "End Send %d bytes to host: %d",recvLen - sizeof(localFd), hostSd);
        // for (int k = 0; k < recvLen - sizeof(localFd); ++k) {
        //     fprintf(stderr, "%c", buf[sizeof(localFd) + k]);
        // }
        // fprintf(stderr, "\n");
        time_t nowT = time(NULL);
        l2hIt->second.lastTime = nowT;
        // h2lMap[hostSd].lastTime = nowT;
    }
    else if (msgType == DebugC2SMsg) {
        LogHelper::log(Debug, "Received Debug C2S msg: %s", buf);
    }
    else {
        LogHelper::log(Warn, "Received Unknown msg type from client: %d", msgType);
        return -8;
    }

    return 0;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x88, %rsp
movq %r9, 0x20(%rsp)
movq %r8, 0x18(%rsp)
movq %rcx, %r13
movq %rdx, %r12
movq %rsi, %rbx
movl %edi, %r14d
movl %edi, 0x10(%rsp)
leaq 0x396c3(%rip), %r15     # 0x3c220
movl $0xffec, %edx           # imm = 0xFFEC
movq %r15, %rdi
xorl %esi, %esi
callq 0x2130
leaq 0x7(%rsp), %r8
movb $0x0, (%r8)
movl $0xffec, %edx           # imm = 0xFFEC
movl %r14d, %edi
movq %r15, %rsi
movq %rbx, %rcx
callq 0x29f1
movl %eax, %ebp
testl %eax, %eax
js 0x2c48
leaq 0x476e(%rip), %rsi      # 0x7307
pushq $0x3
popq %rdi
movl %r14d, %edx
xorl %eax, %eax
callq 0x262c
leaq 0x10(%rsp), %rsi
movq %rbx, %rdi
callq 0x473a
movzbl 0x7(%rsp), %edx
cmpl $0x4, %edx
je 0x2c8a
movq (%rax), %r14
addq $0x18, %r14
cmpl $0x8, %edx
je 0x2c60
cmpl $0x6, %edx
jne 0x2ca9
leaq 0x4759(%rip), %rsi      # 0x733a
pushq $0x3
popq %rdi
xorl %eax, %eax
callq 0x262c
leaq 0x4961e(%rip), %rdi     # 0x4c210
movl $0xff, %edx
xorl %esi, %esi
callq 0x2130
movb 0x3961c(%rip), %al      # 0x3c220
orl $-0x1, 0x8(%rsp)
movzbl 0x39611(%rip), %edx     # 0x3c221
cmpb $0x1, %al
jne 0x2dab
cmpl $0x4, %edx
je 0x2d68
cmpl $0x3, %edx
je 0x2d5a
cmpl $0x1, %edx
jne 0x2d7a
cmpl $0xb, %ebp
ja 0x2e64
leaq 0x470e(%rip), %rsi      # 0x7351
jmp 0x2d9f
leaq 0x4694(%rip), %rsi      # 0x72e3
xorl %edi, %edi
movl %r14d, %edx
xorl %eax, %eax
callq 0x262c
jmp 0x2e19
leaq 0x485c(%rip), %rsi      # 0x74c3
pushq $0x3
popq %rdi
xorl %eax, %eax
callq 0x262c
cmpl $0x3, %ebp
ja 0x2cc2
leaq 0x4861(%rip), %rsi      # 0x74de
xorl %edi, %edi
xorl %eax, %eax
callq 0x262c
pushq $-0x5
jmp 0x2cbc
leaq 0x48cd(%rip), %rsi      # 0x755e
leaq 0x39588(%rip), %rdx     # 0x3c220
pushq $0x3
popq %rdi
xorl %eax, %eax
callq 0x262c
xorl %ebp, %ebp
jmp 0x2e19
leaq 0x48c9(%rip), %rsi      # 0x7579
pushq $0x1
popq %rdi
xorl %eax, %eax
callq 0x262c
pushq $-0x8
popq %rbp
jmp 0x2e19
movl 0x39558(%rip), %eax     # 0x3c220
bswapl %eax
leaq 0x28(%rsp), %rsi
movl %eax, (%rsi)
movq %r14, %rdi
callq 0x51a4
testq %rax, %rax
je 0x2d45
movq %rax, %rbx
movl %ebp, %r15d
leaq 0x28(%rsp), %rsi
movq %r14, %rdi
callq 0x4aac
movl (%rax), %eax
leaq 0x8(%rsp), %r14
movl %eax, (%r14)
movq %r12, %rdi
movq %r14, %rsi
callq 0x4de6
addq $-0x4, %r15
leaq 0x39513(%rip), %rsi     # 0x3c224
movq %rax, %rdi
movq %r15, %rdx
callq 0x3ec0
movl (%r14), %ecx
leaq 0x481a(%rip), %rsi      # 0x7540
xorl %ebp, %ebp
pushq $0x3
popq %rdi
movq %r15, %rdx
xorl %eax, %eax
callq 0x262c
xorl %edi, %edi
callq 0x21a0
movq %rax, 0x18(%rbx)
jmp 0x2e19
movl 0x28(%rsp), %edx
leaq 0x47ce(%rip), %rsi      # 0x751e
xorl %ebp, %ebp
pushq $0x1
popq %rdi
jmp 0x2c54
cmpl $0x2, %ebp
ja 0x2d86
leaq 0x467d(%rip), %rsi      # 0x73e3
jmp 0x2d9f
cmpl $0x17, %ebp
ja 0x2e2d
leaq 0x4622(%rip), %rsi      # 0x739a
jmp 0x2d9f
leaq 0x46b2(%rip), %rsi      # 0x7433
pushq $0x1
popq %rdi
jmp 0x2da4
movzbl 0x39495(%rip), %ecx     # 0x3c222
leal 0x9(%rcx), %eax
cmpl %eax, %ebp
jae 0x2e9b
leaq 0x466d(%rip), %rsi      # 0x740c
pushq $0x1
popq %rdi
movl %ebp, %edx
xorl %eax, %eax
callq 0x262c
pushq $-0x1
popq %r15
movb $-0x1, %r12b
leaq 0x49557(%rip), %r14     # 0x4c310
xorl %ebp, %ebp
movl $0xffec, %edx           # imm = 0xFFEC
movq %r14, %rdi
xorl %esi, %esi
callq 0x2130
movb %r12b, 0x4953f(%rip)    # 0x4c310
movb $0x1, 0x49539(%rip)     # 0x4c311
movw $0xc006, 0x49535(%rip)  # imm = 0xC006
bswapl %r15d
movl %r15d, 0x4952d(%rip)    # 0x4c318
movl 0x10(%rsp), %edi
pushq $0xc
popq %rdx
pushq $0x7
popq %r8
movq %r14, %rsi
movq %rbx, %rcx
callq 0x290a
testl %eax, %eax
jns 0x2e19
movl %eax, %ebx
leaq 0x467e(%rip), %rsi      # 0x748c
xorl %edi, %edi
xorl %eax, %eax
callq 0x262c
movl %ebx, %ebp
movl %ebp, %eax
addq $0x88, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x393ee(%rip), %rsi     # 0x3c222
leaq 0x493d5(%rip), %rdx     # 0x4c210
pushq $0xa
popq %rdi
movl $0xff, %ecx
callq 0x21f0
testq %rax, %rax
je 0x300c
movzwl 0x393da(%rip), %ebp     # 0x3c232
rolw $0x8, %bp
movl 0x393d2(%rip), %eax     # 0x3c234
jmp 0x2ec6
leaq 0x393b7(%rip), %rsi     # 0x3c222
leaq 0x4939e(%rip), %rdx     # 0x4c210
pushq $0x2
popq %rdi
movl $0xff, %ecx
callq 0x21f0
testq %rax, %rax
je 0x3021
movzwl 0x39397(%rip), %ebp     # 0x3c226
rolw $0x8, %bp
movl 0x3938f(%rip), %eax     # 0x3c228
jmp 0x2ec6
leaq 0x4936e(%rip), %rdi     # 0x4c210
leaq 0x3937a(%rip), %rsi     # 0x3c223
movq %rcx, %rdx
movq %rcx, %rbp
callq 0x2160
movq %rbp, %rax
movzwl 0x3(%rbp,%r15), %ebp
rolw $0x8, %bp
movl 0x5(%rax,%r15), %eax
bswapl %eax
movl %eax, 0xc(%rsp)
movl %eax, 0x8(%rsp)
leaq 0x4577(%rip), %rsi      # 0x744e
pushq $0x3
popq %r15
movl %r15d, %edi
xorl %eax, %eax
callq 0x262c
movzwl %bp, %esi
leaq 0x49321(%rip), %rdi     # 0x4c210
pushq $0x1
popq %rdx
callq 0x55f8
movl %eax, %ebp
movl %eax, 0x14(%rsp)
leaq 0x4571(%rip), %rsi      # 0x7475
movl %r15d, %edi
xorl %eax, %eax
callq 0x262c
testl %ebp, %ebp
js 0x2fff
xorl %edi, %edi
callq 0x21a0
movq %rax, %r15
leaq 0x8(%rsp), %rsi
movq %r14, %rdi
movq %rsi, %r14
callq 0x4aac
movl %ebp, (%rax)
movq %r15, 0x8(%rax)
movl 0x10(%rsp), %eax
movl (%r14), %ecx
leaq 0x38(%rsp), %r14
movl %eax, -0x10(%r14)
movl %ecx, -0xc(%r14)
movq %r15, -0x8(%r14)
movq %r14, %rdi
callq 0x3f76
leaq 0x14(%rsp), %rsi
movq %r12, %rdi
callq 0x4de6
movq 0xc0(%rsp), %r15
leaq 0x28(%rsp), %rsi
movq %rax, %rdi
callq 0x3ea4
movq %r14, %rdi
callq 0x426a
movl 0x14(%rsp), %r8d
pushq $0x40
popq %rcx
movl %r8d, %eax
cltd
idivl %ecx
movslq %eax, %rdx
shll $0x6, %eax
movl %r8d, %ecx
subl %eax, %ecx
pushq $0x1
popq %rsi
shlq %cl, %rsi
orq %rsi, (%r13,%rdx,8)
movq 0x20(%rsp), %rdi
movl (%rdi), %eax
cmpl %eax, %r8d
jle 0x2fb6
movl %r8d, (%rdi)
movl %r8d, %eax
movq 0x18(%rsp), %rcx
orq %rsi, (%rcx,%rdx,8)
movq 0xc8(%rsp), %rcx
movl (%r15), %edx
cmpl %edx, %r8d
jle 0x2fd7
movl %r8d, (%r15)
movl (%rdi), %eax
movl %r8d, %edx
cmpl %edx, %eax
cmovgl %eax, %edx
movl %edx, (%rcx)
leaq 0x4498(%rip), %rsi      # 0x747d
xorl %r12d, %r12d
pushq $0x3
popq %rdi
movl %r8d, %edx
xorl %eax, %eax
callq 0x262c
movl 0x8(%rsp), %r15d
jmp 0x2db2
movb $-0x1, %r12b
movl 0xc(%rsp), %r15d
jmp 0x2db2
callq 0x2040
movl (%rax), %edi
callq 0x20d0
leaq 0x43a0(%rip), %rsi      # 0x73bf
jmp 0x3034
callq 0x2040
movl (%rax), %edi
callq 0x20d0
leaq 0x4342(%rip), %rsi      # 0x7376
pushq $0x1
popq %rdi
movq %rax, %rdx
xorl %eax, %eax
callq 0x262c
jmp 0x2dab
movq %rax, %rbx
movq %r14, %rdi
callq 0x426a
movq %rbx, %rdi
callq 0x2310