// File: 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:
subq $0x138, %rsp            # imm = 0x138
movq 0x148(%rsp), %rax
movq 0x140(%rsp), %rax
movl %edi, 0x130(%rsp)
movq %rsi, 0x128(%rsp)
movq %rdx, 0x120(%rsp)
movq %rcx, 0x118(%rsp)
movq %r8, 0x110(%rsp)
movq %r9, 0x108(%rsp)
leaq 0x44223(%rip), %rdi     # 0x47240
xorl %esi, %esi
movl $0xffec, %edx           # imm = 0xFFEC
callq 0x2140
movb $0x0, 0x107(%rsp)
movl 0x130(%rsp), %edi
movq 0x128(%rsp), %rcx
leaq 0x441f9(%rip), %rsi     # 0x47240
movl $0xffec, %edx           # imm = 0xFFEC
leaq 0x107(%rsp), %r8
callq 0x2e10
movl %eax, 0x100(%rsp)
cmpl $0x0, 0x100(%rsp)
jge 0x3094
movl 0x130(%rsp), %edx
xorl %edi, %edi
leaq 0xd26e(%rip), %rsi      # 0x102e8
movb $0x0, %al
callq 0x28f0
movl 0x100(%rsp), %eax
movl %eax, 0x134(%rsp)
jmp 0x38e0
movl 0x130(%rsp), %edx
movl $0x3, %edi
leaq 0xd265(%rip), %rsi      # 0x1030c
movb $0x0, %al
callq 0x28f0
movq 0x128(%rsp), %rdi
leaq 0x130(%rsp), %rsi
callq 0x5650
movq (%rax), %rax
addq $0x18, %rax
movq %rax, 0xf8(%rsp)
movzbl 0x107(%rsp), %eax
cmpl $0x6, %eax
jne 0x371b
movl $0x3, %edi
leaq 0xd250(%rip), %rsi      # 0x1033f
movb $0x0, %al
callq 0x28f0
leaq 0x54133(%rip), %rdi     # 0x57230
xorl %esi, %esi
movl $0xff, %edx
callq 0x2140
movb $0x0, 0xf7(%rsp)
movb 0x44129(%rip), %al      # 0x47240
movb %al, 0xf6(%rsp)
movb 0x4411d(%rip), %al      # 0x47241
movb %al, 0xf5(%rsp)
movl $0xffffffff, 0xf0(%rsp) # imm = 0xFFFFFFFF
movzbl 0xf6(%rsp), %eax
cmpl $0x1, %eax
jne 0x364c
movw $0x0, 0xee(%rsp)
movzbl 0xf5(%rsp), %eax
cmpl $0x1, %eax
jne 0x3210
cmpl $0xc, 0x100(%rsp)
jge 0x3190
movl 0x100(%rsp), %edx
movl $0x1, %edi
leaq 0xd1d7(%rip), %rsi      # 0x10356
movb $0x0, %al
callq 0x28f0
movb $-0x1, 0xf7(%rsp)
jmp 0x320b
movl $0x2, %edi
leaq 0x440a4(%rip), %rsi     # 0x47240
addq $0x2, %rsi
leaq 0x54089(%rip), %rdx     # 0x57230
movl $0xff, %ecx
callq 0x2210
cmpq $0x0, %rax
jne 0x31e3
callq 0x2040
movl (%rax), %edi
callq 0x20e0
movq %rax, %rdx
movl $0x1, %edi
leaq 0xd1a9(%rip), %rsi      # 0x1037b
movb $0x0, %al
callq 0x28f0
movb $-0x1, 0xf7(%rsp)
jmp 0x3209
movzwl 0x4405c(%rip), %edi     # 0x47246
callq 0x2390
movw %ax, 0xee(%rsp)
movl 0x4404b(%rip), %edi     # 0x47248
callq 0x2270
movl %eax, 0xf0(%rsp)
jmp 0x320b
jmp 0x33f0
movzbl 0xf5(%rsp), %eax
cmpl $0x4, %eax
jne 0x32cf
cmpl $0x18, 0x100(%rsp)
jge 0x324f
movl 0x100(%rsp), %edx
movl $0x1, %edi
leaq 0xd161(%rip), %rsi      # 0x1039f
movb $0x0, %al
callq 0x28f0
movb $-0x1, 0xf7(%rsp)
jmp 0x32ca
movl $0xa, %edi
leaq 0x43fe5(%rip), %rsi     # 0x47240
addq $0x2, %rsi
leaq 0x53fca(%rip), %rdx     # 0x57230
movl $0xff, %ecx
callq 0x2210
cmpq $0x0, %rax
jne 0x32a2
callq 0x2040
movl (%rax), %edi
callq 0x20e0
movq %rax, %rdx
movl $0x1, %edi
leaq 0xd133(%rip), %rsi      # 0x103c4
movb $0x0, %al
callq 0x28f0
movb $-0x1, 0xf7(%rsp)
jmp 0x32c8
movzwl 0x43fa9(%rip), %edi     # 0x47252
callq 0x2390
movw %ax, 0xee(%rsp)
movl 0x43f98(%rip), %edi     # 0x47254
callq 0x2270
movl %eax, 0xf0(%rsp)
jmp 0x32ca
jmp 0x33ee
movzbl 0xf5(%rsp), %eax
cmpl $0x3, %eax
jne 0x33c9
cmpl $0x3, 0x100(%rsp)
jge 0x3311
movl 0x100(%rsp), %edx
movl $0x1, %edi
leaq 0xd0eb(%rip), %rsi      # 0x103e8
movb $0x0, %al
callq 0x28f0
movb $-0x1, 0xf7(%rsp)
jmp 0x33c7
movb 0x43f2b(%rip), %al      # 0x47242
movb %al, 0xed(%rsp)
movl 0x100(%rsp), %eax
movzbl 0xed(%rsp), %ecx
addl $0x3, %ecx
addl $0x2, %ecx
addl $0x4, %ecx
cmpl %ecx, %eax
jge 0x335e
movl 0x100(%rsp), %edx
movl $0x1, %edi
leaq 0xd0c4(%rip), %rsi      # 0x10411
movb $0x0, %al
callq 0x28f0
movb $-0x1, 0xf7(%rsp)
jmp 0x33c5
movzbl 0xed(%rsp), %eax
movl %eax, %edx
leaq 0x53ec1(%rip), %rdi     # 0x57230
leaq 0x43eca(%rip), %rsi     # 0x47240
addq $0x3, %rsi
callq 0x2180
movzbl 0xed(%rsp), %eax
movslq %eax, %rcx
leaq 0x43eaf(%rip), %rax     # 0x47240
movzwl 0x3(%rax,%rcx), %edi
callq 0x2390
movw %ax, 0xee(%rsp)
movzbl 0xed(%rsp), %eax
movslq %eax, %rcx
leaq 0x43e8b(%rip), %rax     # 0x47240
movl 0x5(%rax,%rcx), %edi
callq 0x2270
movl %eax, 0xf0(%rsp)
jmp 0x33c7
jmp 0x33ec
movzbl 0xf5(%rsp), %edx
movl $0x1, %edi
leaq 0xd05b(%rip), %rsi      # 0x10438
movb $0x0, %al
callq 0x28f0
movb $-0x1, 0xf7(%rsp)
jmp 0x33ee
jmp 0x33f0
movzbl 0xf7(%rsp), %eax
cmpl $0x0, %eax
jne 0x364a
movl $0x3, %edi
leaq 0xd046(%rip), %rsi      # 0x10453
movb $0x0, %al
callq 0x28f0
leaq 0x53e15(%rip), %rdi     # 0x57230
movl $0x1, %edx
movzwl 0xee(%rsp), %esi
callq 0xc4e0
movl %eax, 0xe8(%rsp)
movl $0x3, %edi
leaq 0xd03a(%rip), %rsi      # 0x1047a
movb $0x0, %al
callq 0x28f0
cmpl $0x0, 0xe8(%rsp)
jge 0x345e
movb $-0x1, 0xf7(%rsp)
jmp 0x3648
xorl %eax, %eax
movl %eax, %edi
callq 0x21c0
movq %rax, 0xe0(%rsp)
movl 0xe8(%rsp), %esi
movq 0xe0(%rsp), %rdx
leaq 0xd0(%rsp), %rdi
callq 0x5680
movq 0xf8(%rsp), %rdi
leaq 0xf0(%rsp), %rsi
callq 0x56b0
movups 0xd0(%rsp), %xmm0
movups %xmm0, (%rax)
movl 0x130(%rsp), %esi
movl 0xf0(%rsp), %edx
movq 0xe0(%rsp), %rcx
leaq 0x70(%rsp), %rdi
callq 0x56e0
movq 0x120(%rsp), %rdi
leaq 0xe8(%rsp), %rsi
callq 0x5720
movq %rax, 0x28(%rsp)
jmp 0x34e7
movq 0x28(%rsp), %rdi
leaq 0x70(%rsp), %rsi
callq 0x5750
leaq 0x70(%rsp), %rdi
callq 0x57a0
movl 0xe8(%rsp), %eax
movl $0x40, %ecx
cltd
idivl %ecx
movl %edx, %eax
movl %eax, %ecx
movl $0x1, %eax
shlq %cl, %rax
movq %rax, 0x18(%rsp)
movq 0x118(%rsp), %rax
movq %rax, 0x20(%rsp)
movl 0xe8(%rsp), %eax
movl $0x40, %ecx
cltd
idivl %ecx
movq 0x18(%rsp), %rdx
movl %eax, %ecx
movq 0x20(%rsp), %rax
movslq %ecx, %rcx
orq (%rax,%rcx,8), %rdx
movq %rdx, (%rax,%rcx,8)
movl 0xe8(%rsp), %eax
movq 0x108(%rsp), %rcx
cmpl (%rcx), %eax
jle 0x3596
movl 0xe8(%rsp), %ecx
movq 0x108(%rsp), %rax
movl %ecx, (%rax)
jmp 0x3596
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x68(%rsp)
movl %eax, 0x64(%rsp)
leaq 0x70(%rsp), %rdi
callq 0x57a0
jmp 0x38ef
movl 0xe8(%rsp), %eax
movl $0x40, %ecx
cltd
idivl %ecx
movl %edx, %eax
movl %eax, %ecx
movl $0x1, %eax
shlq %cl, %rax
movq %rax, 0x8(%rsp)
movq 0x110(%rsp), %rax
movq %rax, 0x10(%rsp)
movl 0xe8(%rsp), %eax
movl $0x40, %ecx
cltd
idivl %ecx
movq 0x8(%rsp), %rdx
movl %eax, %ecx
movq 0x10(%rsp), %rax
movslq %ecx, %rcx
orq (%rax,%rcx,8), %rdx
movq %rdx, (%rax,%rcx,8)
movl 0xe8(%rsp), %eax
movq 0x140(%rsp), %rcx
cmpl (%rcx), %eax
jle 0x360d
movl 0xe8(%rsp), %ecx
movq 0x140(%rsp), %rax
movl %ecx, (%rax)
movq 0x108(%rsp), %rdi
movq 0x140(%rsp), %rsi
callq 0x57c0
movl (%rax), %ecx
movq 0x148(%rsp), %rax
movl %ecx, (%rax)
movl 0xe8(%rsp), %edx
movl $0x3, %edi
leaq 0xce41(%rip), %rsi      # 0x10482
movb $0x0, %al
callq 0x28f0
jmp 0x364a
jmp 0x3654
movb $-0x1, 0xf7(%rsp)
leaq 0x53cd5(%rip), %rdi     # 0x57330
xorl %esi, %esi
movl $0xffec, %edx           # imm = 0xFFEC
callq 0x2140
movb 0xf7(%rsp), %al
movb %al, 0x53cbc(%rip)      # 0x57330
movb $0x1, 0x53cb6(%rip)     # 0x57331
leaq 0x53cae(%rip), %rdi     # 0x57330
addq $0x2, %rdi
xorl %esi, %esi
movl $0x4, %edx
callq 0x2140
movw $0x6c0, 0x62(%rsp)      # imm = 0x6C0
movzwl 0x62(%rsp), %edi
callq 0x2060
movw %ax, 0x53c8c(%rip)      # 0x57336
movl 0xf0(%rsp), %edi
callq 0x2160
movl %eax, 0x53c7c(%rip)     # 0x57338
movq $0xc, 0x58(%rsp)
movl 0x130(%rsp), %edi
movq 0x58(%rsp), %rdx
movq 0x128(%rsp), %rcx
leaq 0x53c50(%rip), %rsi     # 0x57330
movl $0x7, %r8d
callq 0x2cd0
movl %eax, 0x54(%rsp)
cmpl $0x0, 0x54(%rsp)
jge 0x3716
xorl %edi, %edi
leaq 0xcd92(%rip), %rsi      # 0x10491
movb $0x0, %al
callq 0x28f0
movl 0x54(%rsp), %eax
movl %eax, 0x134(%rsp)
jmp 0x38e0
jmp 0x38d5
movzbl 0x107(%rsp), %eax
cmpl $0x8, %eax
jne 0x3880
movl $0x3, %edi
leaq 0xcd90(%rip), %rsi      # 0x104c8
movb $0x0, %al
callq 0x28f0
movl $0xffffffff, 0x50(%rsp) # imm = 0xFFFFFFFF
movslq 0x100(%rsp), %rax
cmpq $0x4, %rax
jae 0x3775
xorl %edi, %edi
leaq 0xcd85(%rip), %rsi      # 0x104e3
movb $0x0, %al
callq 0x28f0
movl $0xfffffffb, 0x134(%rsp) # imm = 0xFFFFFFFB
jmp 0x38e0
movl 0x43ac5(%rip), %edi     # 0x47240
callq 0x2270
movl %eax, 0x50(%rsp)
movq 0xf8(%rsp), %rdi
leaq 0x50(%rsp), %rsi
callq 0x5800
movq %rax, 0x48(%rsp)
movq 0xf8(%rsp), %rdi
callq 0x5850
movq %rax, 0x40(%rsp)
leaq 0x48(%rsp), %rdi
leaq 0x40(%rsp), %rsi
callq 0x5830
testb $0x1, %al
jne 0x37c2
jmp 0x37e9
movl 0x50(%rsp), %edx
movl $0x1, %edi
leaq 0xcd51(%rip), %rsi      # 0x10523
movb $0x0, %al
callq 0x28f0
movl $0x0, 0x134(%rsp)
jmp 0x38e0
movq 0xf8(%rsp), %rdi
leaq 0x50(%rsp), %rsi
callq 0x56b0
movl (%rax), %eax
movl %eax, 0x3c(%rsp)
movq 0x120(%rsp), %rdi
leaq 0x3c(%rsp), %rsi
callq 0x5720
movq %rax, %rdi
movslq 0x100(%rsp), %rdx
subq $0x4, %rdx
leaq 0x43a17(%rip), %rsi     # 0x47240
addq $0x4, %rsi
callq 0x5880
movslq 0x100(%rsp), %rdx
subq $0x4, %rdx
movl 0x3c(%rsp), %ecx
movl $0x3, %edi
leaq 0xccf7(%rip), %rsi      # 0x10545
movb $0x0, %al
callq 0x28f0
xorl %eax, %eax
movl %eax, %edi
callq 0x21c0
movq %rax, 0x30(%rsp)
movq 0x30(%rsp), %rax
movq %rax, (%rsp)
leaq 0x48(%rsp), %rdi
callq 0x58e0
movq (%rsp), %rcx
movq %rcx, 0x10(%rax)
jmp 0x38d3
movzbl 0x107(%rsp), %eax
cmpl $0x4, %eax
jne 0x38a9
movl $0x3, %edi
leaq 0xccca(%rip), %rsi      # 0x10563
leaq 0x439a0(%rip), %rdx     # 0x47240
movb $0x0, %al
callq 0x28f0
jmp 0x38d1
movzbl 0x107(%rsp), %edx
movl $0x1, %edi
leaq 0xccc1(%rip), %rsi      # 0x1057e
movb $0x0, %al
callq 0x28f0
movl $0xfffffff8, 0x134(%rsp) # imm = 0xFFFFFFF8
jmp 0x38e0
jmp 0x38d3
jmp 0x38d5
movl $0x0, 0x134(%rsp)
movl 0x134(%rsp), %eax
addq $0x138, %rsp            # imm = 0x138
retq
movq 0x68(%rsp), %rdi
callq 0x2360
nopl (%rax)