// File: /workspace/github_cpp_makefile_star2_O3/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 0x3959c(%rip), %r15     # 0x3c210
movl $0xffec, %edx           # imm = 0xFFEC
movq %r15, %rdi
xorl %esi, %esi
callq 0x2120
leaq 0xb(%rsp), %r8
movb $0x0, (%r8)
movl $0xffec, %edx           # imm = 0xFFEC
movl %r14d, %edi
movq %r15, %rsi
movq %rbx, %rcx
callq 0x2afc
movl %eax, %ebp
testl %eax, %eax
js 0x2d73
leaq 0x4657(%rip), %rsi      # 0x7307
movl $0x3, %edi
movl %r14d, %edx
xorl %eax, %eax
callq 0x273c
leaq 0x10(%rsp), %rsi
movq %rbx, %rdi
callq 0x48c8
movzbl 0xb(%rsp), %edx
cmpl $0x4, %edx
je 0x2dbd
movq (%rax), %r14
addq $0x18, %r14
cmpl $0x8, %edx
je 0x2d8b
cmpl $0x6, %edx
jne 0x2dde
leaq 0x4640(%rip), %rsi      # 0x733a
movl $0x3, %edi
xorl %eax, %eax
callq 0x273c
leaq 0x494f3(%rip), %rdi     # 0x4c200
movl $0xff, %edx
xorl %esi, %esi
callq 0x2120
movb 0x394f1(%rip), %al      # 0x3c210
movzbl 0x394eb(%rip), %edx     # 0x3c211
movl $0xffffffff, 0xc(%rsp)  # imm = 0xFFFFFFFF
cmpb $0x1, %al
jne 0x2ef3
cmpl $0x4, %edx
je 0x2ea5
cmpl $0x3, %edx
je 0x2e97
cmpl $0x1, %edx
movl $0xffffffff, %r15d      # imm = 0xFFFFFFFF
jne 0x2eb7
cmpl $0xb, %ebp
ja 0x2fbb
leaq 0x45ea(%rip), %rsi      # 0x7351
movl $0x1, %edi
movl %ebp, %edx
jmp 0x2ec3
leaq 0x4569(%rip), %rsi      # 0x72e3
xorl %edi, %edi
movl %r14d, %edx
xorl %eax, %eax
callq 0x273c
jmp 0x2f67
leaq 0x4731(%rip), %rsi      # 0x74c3
movl $0x3, %edi
xorl %eax, %eax
callq 0x273c
cmpl $0x3, %ebp
ja 0x2dfb
leaq 0x4734(%rip), %rsi      # 0x74de
xorl %edi, %edi
xorl %eax, %eax
callq 0x273c
movl $0xfffffffb, %ebp       # imm = 0xFFFFFFFB
jmp 0x2f67
leaq 0x479a(%rip), %rsi      # 0x755e
leaq 0x39445(%rip), %rdx     # 0x3c210
movl $0x3, %edi
xorl %eax, %eax
callq 0x273c
xorl %ebp, %ebp
jmp 0x2f67
leaq 0x4794(%rip), %rsi      # 0x7579
movl $0x1, %edi
xorl %eax, %eax
callq 0x273c
movl $0xfffffff8, %ebp       # imm = 0xFFFFFFF8
jmp 0x2f67
movl 0x3940f(%rip), %eax     # 0x3c210
bswapl %eax
leaq 0x28(%rsp), %rsi
movl %eax, (%rsi)
movq %r14, %rdi
callq 0x511e
testq %rax, %rax
je 0x2e80
movq %rax, %rbx
movl %ebp, %r15d
leaq 0x28(%rsp), %rsi
movq %r14, %rdi
callq 0x4b68
movl (%rax), %eax
leaq 0xc(%rsp), %r14
movl %eax, (%r14)
movq %r12, %rdi
movq %r14, %rsi
callq 0x4df4
addq $-0x4, %r15
leaq 0x393ca(%rip), %rsi     # 0x3c214
movq %rax, %rdi
movq %r15, %rdx
callq 0x41ec
movl (%r14), %ecx
leaq 0x46e1(%rip), %rsi      # 0x7540
xorl %ebp, %ebp
movl $0x3, %edi
movq %r15, %rdx
xorl %eax, %eax
callq 0x273c
xorl %edi, %edi
callq 0x2190
movq %rax, 0x18(%rbx)
jmp 0x2f67
movl 0x28(%rsp), %edx
leaq 0x4693(%rip), %rsi      # 0x751e
xorl %ebp, %ebp
movl $0x1, %edi
jmp 0x2d7f
cmpl $0x2, %ebp
ja 0x2ecc
leaq 0x4540(%rip), %rsi      # 0x73e3
jmp 0x2ee5
cmpl $0x17, %ebp
ja 0x2f7b
leaq 0x44e5(%rip), %rsi      # 0x739a
jmp 0x2ee5
leaq 0x4575(%rip), %rsi      # 0x7433
movl $0x1, %edi
xorl %eax, %eax
callq 0x273c
jmp 0x2ef9
movzbl 0x3933f(%rip), %ecx     # 0x3c212
leal 0x9(%rcx), %eax
cmpl %eax, %ebp
jae 0x2ff5
leaq 0x4527(%rip), %rsi      # 0x740c
movl $0x1, %edi
movl %ebp, %edx
xorl %eax, %eax
callq 0x273c
movl $0xffffffff, %r15d      # imm = 0xFFFFFFFF
movb $-0x1, %r12b
leaq 0x493fd(%rip), %r14     # 0x4c300
xorl %ebp, %ebp
movl $0xffec, %edx           # imm = 0xFFEC
movq %r14, %rdi
xorl %esi, %esi
callq 0x2120
movb %r12b, 0x493e5(%rip)    # 0x4c300
movb $0x1, 0x493df(%rip)     # 0x4c301
movw $0xc006, 0x493db(%rip)  # imm = 0xC006
bswapl %r15d
movl %r15d, 0x493d3(%rip)    # 0x4c308
movl 0x10(%rsp), %edi
movl $0xc, %edx
movq %r14, %rsi
movq %rbx, %rcx
movl $0x7, %r8d
callq 0x2a11
testl %eax, %eax
jns 0x2f67
movl %eax, %ebx
leaq 0x4530(%rip), %rsi      # 0x748c
xorl %edi, %edi
xorl %eax, %eax
callq 0x273c
movl %ebx, %ebp
movl %ebp, %eax
addq $0x88, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x39290(%rip), %rsi     # 0x3c212
leaq 0x49277(%rip), %rdx     # 0x4c200
movl $0xa, %edi
movl $0xff, %ecx
callq 0x21e0
testq %rax, %rax
movl $0xffffffff, %r15d      # imm = 0xFFFFFFFF
je 0x317e
movzwl 0x39274(%rip), %ebp     # 0x3c222
rolw $0x8, %bp
movl 0x3926b(%rip), %r15d    # 0x3c224
jmp 0x3020
leaq 0x39250(%rip), %rsi     # 0x3c212
leaq 0x49237(%rip), %rdx     # 0x4c200
movl $0x2, %edi
movl $0xff, %ecx
callq 0x21e0
testq %rax, %rax
je 0x3193
movzwl 0x3922e(%rip), %ebp     # 0x3c216
rolw $0x8, %bp
movl 0x39225(%rip), %r15d    # 0x3c218
jmp 0x3020
leaq 0x49204(%rip), %rdi     # 0x4c200
leaq 0x39210(%rip), %rsi     # 0x3c213
movq %rcx, %rdx
movq %rcx, %rbp
callq 0x2150
movq %rbp, %rax
movzwl 0x3(%rbp,%r15), %ebp
rolw $0x8, %bp
movl 0x5(%rax,%r15), %r15d
bswapl %r15d
movl %r15d, 0xc(%rsp)
leaq 0x441f(%rip), %rsi      # 0x744e
movl $0x3, %edi
xorl %eax, %eax
callq 0x273c
movzwl %bp, %esi
leaq 0x491bb(%rip), %rdi     # 0x4c200
movl $0x1, %edx
callq 0x54d0
movl %eax, %ebp
movl %eax, 0x14(%rsp)
leaq 0x4419(%rip), %rsi      # 0x7475
movl $0x3, %edi
xorl %eax, %eax
callq 0x273c
testl %ebp, %ebp
js 0x2ef9
xorl %edi, %edi
callq 0x2190
movq %rax, %r15
leaq 0xc(%rsp), %rsi
movq %r14, %rdi
movq %rsi, %r14
callq 0x4b68
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)
xorps %xmm0, %xmm0
movups %xmm0, (%r14)
movups %xmm0, 0x10(%r14)
movups %xmm0, 0x20(%r14)
movups %xmm0, 0x30(%r14)
movups %xmm0, 0x40(%r14)
movq %r14, %rdi
xorl %esi, %esi
callq 0x42ce
leaq 0x14(%rsp), %rsi
movq %r12, %rdi
callq 0x4df4
movq 0xc0(%rsp), %r15
movups 0x28(%rsp), %xmm0
movups %xmm0, (%rax)
addq $0x10, %rax
movq %rax, %rdi
movq %r14, %rsi
callq 0x4444
movq %r14, %rdi
callq 0x44fa
movl 0x14(%rsp), %edx
leal 0x3f(%rdx), %eax
testl %edx, %edx
cmovnsl %edx, %eax
movl %eax, %esi
andl $-0x40, %esi
movl %edx, %ecx
subl %esi, %ecx
movl $0x1, %esi
shlq %cl, %rsi
sarl $0x6, %eax
movslq %eax, %rcx
orq %rsi, (%r13,%rcx,8)
movq 0x20(%rsp), %rdi
movl (%rdi), %eax
cmpl %eax, %edx
jle 0x3138
movl %edx, (%rdi)
movl %edx, %eax
movq 0x18(%rsp), %r8
orq %rsi, (%r8,%rcx,8)
movq 0xc8(%rsp), %rcx
movl (%r15), %esi
cmpl %esi, %edx
jle 0x3157
movl %edx, (%r15)
movl (%rdi), %eax
movl %edx, %esi
cmpl %esi, %eax
cmovgl %eax, %esi
movl %esi, (%rcx)
leaq 0x4318(%rip), %rsi      # 0x747d
xorl %r12d, %r12d
movl $0x3, %edi
xorl %eax, %eax
callq 0x273c
movl 0xc(%rsp), %r15d
jmp 0x2efc
callq 0x2040
movl (%rax), %edi
callq 0x20d0
leaq 0x422e(%rip), %rsi      # 0x73bf
jmp 0x31a6
callq 0x2040
movl (%rax), %edi
callq 0x20d0
leaq 0x41d0(%rip), %rsi      # 0x7376
movl $0x1, %edi
movq %rax, %rdx
xorl %eax, %eax
callq 0x273c
jmp 0x2ef9
movq %rax, %rbx
movq %r14, %rdi
callq 0x44fa
movq %rbx, %rdi
callq 0x2310