// File: /workspace/github_cpp_makefile_star2_O2/renzibei[P]TSProxy/proxyclient.cpp
// Function: startListen(int, ClientContext*)
int startListen(int serverFd, ClientContext *ctx) {
    int on = 1;
    int listen_sd = make_socket(constants::clientListenPort, on, constants::clientBindToLoopback);
    if (listen_sd < 0) {
        LogHelper::log(Error, "Client fail to make listen socket");
        return -1;
    }

    // set nonblocking
    int rc = ioctl(listen_sd, FIONBIO, (char *)&on);
    if (rc < 0) {
        // perror("ioctl() failed");
        LogHelper::log(Error, "failed to ioctl(), %s", strerror(errno));
        close(listen_sd);
        // exit(-1);
        return -2;
    }

    // rc = ioctl(serverFd, FIONBIO, (char *)&on);
    // if (rc < 0) {
    //     // perror("ioctl() failed");
    //     LogHelper::log(Error, "failed to ioctl(), %s", strerror(errno));
    //     close(serverFd);
    //     // exit(-1);
    //     return -2;
    // }

    rc = listen(listen_sd, 1024);
    if (rc < 0) {
        LogHelper::log(Error, "Failed to listen, %s", strerror(errno));
        close(listen_sd);
        return -3;
    }

    fd_set master_set, working_set;
    FD_ZERO(&master_set);
    int max_sd = listen_sd;
    FD_SET(listen_sd, &master_set);

    FD_SET(serverFd, &master_set);
    if (serverFd > max_sd) {
        max_sd = serverFd;
    }

    struct timeval timeout;
    timeout.tv_sec  = 3 * 60;
    timeout.tv_usec = 0;

    LocalFdMap localFdMap;
    LogHelper::log(Info, "Begin loop");
    bool endLoop = false;
    do {
        memcpy(&working_set, &master_set, sizeof(master_set));
        LogHelper::log(Debug, "Client waiting for select");
        rc = select(max_sd + 1, &working_set, NULL, NULL, &timeout);
        if (rc < 0) {
            LogHelper::log(Error, "Error when select, %s", strerror(errno));
            return -4;
        }
        if (rc == 0) {
            LogHelper::log(Debug, "select time out, continue");
            continue;
        }
        int ready_fds = rc;
        LogHelper::log(Debug, "read_fd num: %d", ready_fds);
        for (int i = 0; i <= max_sd && ready_fds > 0; ++i) {
            if (FD_ISSET(i, &working_set)) {
                ready_fds--;
                if (i == listen_sd) {
                    LogHelper::log(Debug, "Listen socket is readable");
                    int new_sd = -1;
                    do {
                        new_sd = accept(listen_sd, NULL, NULL);
                        if (new_sd < 0) {
                            if (errno != EAGAIN) {
                                // perror("  accept() failed");
                                LogHelper::log(Error, "accept failed, %s", strerror(errno));
                                endLoop = true;
                            }
                            break;
                        }

                        LogHelper::log(Debug, "New incoming connection fd: %d\n", new_sd);
                        FD_SET(new_sd, &master_set);
                        if (new_sd > max_sd)
                            max_sd = new_sd;
                        
                        rc = socksHandShake(new_sd, serverFd, ctx, localFdMap);
                        if (rc < 0) {
                            LogHelper::log(Error, "Failed to establish socks connection, clean fd: %d", new_sd);
                            close(new_sd);
                            FD_CLR(new_sd, &master_set);
                            if (new_sd == max_sd) {
                                while (FD_ISSET(max_sd, &master_set) == 0)
                                    max_sd -= 1;
                            }
                            if (localFdMap.find(new_sd) != localFdMap.end()) {
                                localFdMap.erase(new_sd);
                            }
                        }
                    } while (new_sd != -1);
                }
                else if(i == serverFd) {
                    LogHelper::log(Debug, "Server Fd is readable");

                    int handleRet = readAndHandleFromServer(i, localFdMap, ctx, master_set, max_sd);

                    
                }
                else {
                    LogHelper::log(Debug, "Fd %d is ready", i);
                    bool close_conn = false;
                    static char readBuf2[constants::AES_MAX_DATA_LENGTH - 72];
                    memset(readBuf2, 0, sizeof(readBuf2));
                    rc = recv(i, readBuf2, sizeof(readBuf2), 0);
                    if (rc < 0) {
                        if (errno != EAGAIN) {
                            LogHelper::log(Error, "Failed in recv of %d fd", i);
                            close_conn = true;
                        }
                        
                    }
                    else if (rc == 0) {
                        LogHelper::log(Warn, "Fd %d has been closed", i);
                        close_conn = true;
                    }
                    else {
                        LogHelper::log(Debug, "recv from socks user %d bytes, : %s", rc, readBuf2);
                        int sendCode = sendRequestMsg(serverFd, i, (const uint8_t *)readBuf2, rc, ctx);
                        if (sendCode < 0) {
                            LogHelper::log(Error, "Fail to send local data to server");
                            return sendCode;
                        }
                    }

                    if (close_conn) {
                        LogHelper::log(Warn, "Close fd: %d", i);
                        close(i);
                        FD_CLR(i, &master_set);
                        if (i == max_sd) {
                            while (FD_ISSET(max_sd, &master_set) == 0)
                                max_sd -= 1;
                        }
                        if (localFdMap.find(i) != localFdMap.end()) {
                            localFdMap.erase(i);
                        }
                    }
                }
            }
        }

    } while(!endLoop);

    return 0;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x168, %rsp            # imm = 0x168
movq %rsi, 0x10(%rsp)
movl %edi, %ebp
movl $0x1, 0x1c(%rsp)
pushq $0x1
popq %rsi
movl $0x2b48, %edi           # imm = 0x2B48
xorl %edx, %edx
callq 0x4508
testl %eax, %eax
js 0x3549
movl %eax, %ebx
leaq 0x1c(%rsp), %rdx
movl $0x5421, %esi           # imm = 0x5421
movl %eax, %edi
xorl %eax, %eax
callq 0x22e0
testl %eax, %eax
js 0x3967
movl %ebx, %edi
movl $0x400, %esi            # imm = 0x400
callq 0x2240
testl %eax, %eax
js 0x39c0
xorl %eax, %eax
cmpq $0x10, %rax
je 0x3560
andq $0x0, 0x68(%rsp,%rax,8)
incq %rax
jmp 0x3538
leaq 0x33c1(%rip), %rsi      # 0x6911
xorl %edi, %edi
xorl %eax, %eax
callq 0x26e8
pushq $-0x1
jmp 0x39e8
pushq $0x1
popq %rsi
movq %rsi, %rax
movl %ebx, %ecx
shlq %cl, %rax
movl %ebx, %ecx
shrl $0x6, %ecx
orq %rax, 0x68(%rsp,%rcx,8)
movl %ebx, 0x8(%rsp)
pushq $0x40
popq %r14
movl %ebp, %eax
cltd
idivl %r14d
movslq %eax, %rdx
shll $0x6, %eax
movl %ebp, %ecx
subl %eax, %ecx
movq %rsi, %rax
shlq %cl, %rax
orq %rax, 0x68(%rsp,%rdx,8)
movl %ebx, %r12d
cmpl %ebp, %ebx
jge 0x35a6
movl %ebp, 0x8(%rsp)
movl %ebp, %r12d
movq $0xb4, 0x20(%rsp)
andq $0x0, 0x28(%rsp)
leaq 0x60(%rsp), %rax
movq %rax, -0x30(%rax)
movq $0x1, -0x28(%rax)
xorps %xmm0, %xmm0
movups %xmm0, -0x20(%rax)
movl $0x3f800000, -0x10(%rax) # imm = 0x3F800000
movups %xmm0, -0x8(%rax)
leaq 0x337f(%rip), %rsi      # 0x695e
pushq $0x2
popq %rdi
xorl %eax, %eax
callq 0x26e8
leal 0x1(%r12), %r15d
pushq $0x10
popq %rcx
leaq 0xe8(%rsp), %rdi
leaq 0x68(%rsp), %rsi
rep  movsq (%rsi), %es:(%rdi)
pushq $0x3
popq %rdi
leaq 0x335e(%rip), %rsi      # 0x6969
xorl %eax, %eax
callq 0x26e8
movl %r15d, %edi
leaq 0xe8(%rsp), %rsi
xorl %edx, %edx
xorl %ecx, %ecx
leaq 0x20(%rsp), %r8
callq 0x2200
movl %eax, %r13d
testl %eax, %eax
js 0x3991
jne 0x364b
pushq $0x3
popq %rdi
leaq 0x3357(%rip), %rsi      # 0x6999
xorl %eax, %eax
callq 0x26e8
jmp 0x35ee
pushq $0x3
popq %rdi
leaq 0x335e(%rip), %rsi      # 0x69b3
movl %r13d, %edx
xorl %eax, %eax
callq 0x26e8
xorl %ecx, %ecx
movl $0x0, 0xc(%rsp)
movl %ecx, (%rsp)
cmpl %r12d, %ecx
jg 0x3957
testl %r13d, %r13d
jle 0x3957
movl %ecx, %eax
cltd
idivl %r14d
cltq
movq 0xe8(%rsp,%rax,8), %rax
btq %rdx, %rax
jae 0x394d
decl %r13d
cmpl %ebx, %ecx
jne 0x37ad
pushq $0x3
popq %rdi
leaq 0x3316(%rip), %rsi      # 0x69c3
xorl %eax, %eax
callq 0x26e8
pushq $0x1
popq %r15
orl $-0x1, 0x4(%rsp)
movl %ebx, %edi
xorl %esi, %esi
xorl %edx, %edx
callq 0x20c0
movl %eax, 0x4(%rsp)
testl %eax, %eax
js 0x37e8
pushq $0x3
popq %rdi
leaq 0x3311(%rip), %rsi      # 0x69ef
movl %eax, %edx
xorl %eax, %eax
callq 0x26e8
movl 0x4(%rsp), %edi
movl %edi, %eax
cltd
idivl %r14d
movslq %eax, %rdx
shll $0x6, %eax
movl %edi, %ecx
subl %eax, %ecx
movq %r15, %rax
shlq %cl, %rax
orq %rax, 0x68(%rsp,%rdx,8)
cmpl %r12d, %edi
cmovgl %edi, %r12d
movl %ebp, %esi
movq 0x10(%rsp), %rdx
leaq 0x30(%rsp), %rcx
callq 0x2df1
testl %eax, %eax
jns 0x3798
movl 0x4(%rsp), %edx
xorl %edi, %edi
leaq 0x32e0(%rip), %rsi      # 0x6a0f
xorl %eax, %eax
callq 0x26e8
movl 0x4(%rsp), %edi
callq 0x2390
movl 0x4(%rsp), %ecx
pushq $-0x2
popq %rsi
rolq %cl, %rsi
movl %ecx, %eax
cltd
idivl %r14d
cltq
andq %rsi, 0x68(%rsp,%rax,8)
cmpl %r12d, %ecx
jne 0x3775
movl %r12d, %eax
cltd
idivl %r14d
cltq
movq 0x68(%rsp,%rax,8), %rax
decl %r12d
btq %rdx, %rax
jae 0x375b
incl %r12d
leaq 0x30(%rsp), %rdi
leaq 0x4(%rsp), %rsi
callq 0x40ca
testq %rax, %rax
je 0x3798
leaq 0x30(%rsp), %rdi
leaq 0x4(%rsp), %rsi
callq 0x40e8
cmpl $-0x1, 0x4(%rsp)
jne 0x36bd
movl %r12d, 0x8(%rsp)
jmp 0x394d
cmpl %ebp, %ecx
jne 0x3820
pushq $0x3
popq %rdi
leaq 0x3287(%rip), %rsi      # 0x6a42
xorl %eax, %eax
callq 0x26e8
movl (%rsp), %edi
leaq 0x30(%rsp), %rsi
movq 0x10(%rsp), %rdx
leaq 0x68(%rsp), %rcx
leaq 0x8(%rsp), %r8
callq 0x31cb
movl 0x8(%rsp), %r12d
jmp 0x394d
movl %r12d, 0x8(%rsp)
callq 0x2040
movl (%rax), %edi
cmpl $0xb, %edi
je 0x394d
callq 0x20e0
movb $0x1, %cl
movl %ecx, 0xc(%rsp)
xorl %edi, %edi
leaq 0x31cc(%rip), %rsi      # 0x69dd
movq %rax, %rdx
xorl %eax, %eax
callq 0x26e8
jmp 0x394d
pushq $0x3
popq %rdi
leaq 0x322e(%rip), %rsi      # 0x6a58
movl %ecx, %edx
xorl %eax, %eax
callq 0x26e8
movl $0xff84, %edx           # imm = 0xFF84
leaq 0x77cf1(%rip), %r15     # 0x7b530
movq %r15, %rdi
xorl %esi, %esi
callq 0x2140
movl (%rsp), %edi
movl $0xff84, %edx           # imm = 0xFF84
movq %r15, %rsi
xorl %ecx, %ecx
callq 0x20d0
movq %rax, %r15
testl %r15d, %r15d
js 0x38bb
pushq $0x1
popq %rdi
leaq 0x3212(%rip), %rsi      # 0x6a7f
je 0x38ce
pushq $0x3
popq %rdi
leaq 0x321c(%rip), %rsi      # 0x6a95
movl %r15d, %edx
leaq 0x77cad(%rip), %rcx     # 0x7b530
xorl %eax, %eax
callq 0x26e8
movl (%rsp), %esi
andl $0x7fffffff, %r15d      # imm = 0x7FFFFFFF
movl %ebp, %edi
leaq 0x77c93(%rip), %rdx     # 0x7b530
movq %r15, %rcx
movq 0x10(%rsp), %r8
callq 0x2a1f
movq %rax, %r15
testl %r15d, %r15d
jns 0x394d
jmp 0x39ff
callq 0x2040
xorl %edi, %edi
cmpl $0xb, (%rax)
leaq 0x319b(%rip), %rsi      # 0x6a67
je 0x394d
movl (%rsp), %edx
xorl %eax, %eax
callq 0x26e8
movl (%rsp), %edx
pushq $0x1
popq %rdi
leaq 0x31f6(%rip), %rsi      # 0x6adb
xorl %eax, %eax
callq 0x26e8
movl (%rsp), %edi
callq 0x2390
movl (%rsp), %ecx
pushq $-0x2
popq %rsi
rolq %cl, %rsi
movl %ecx, %eax
cltd
idivl %r14d
cltq
andq %rsi, 0x68(%rsp,%rax,8)
cmpl %r12d, %ecx
jne 0x392e
movl %r12d, %eax
cltd
idivl %r14d
cltq
movq 0x68(%rsp,%rax,8), %rax
decl %r12d
btq %rdx, %rax
jae 0x390f
incl %r12d
movl %r12d, 0x8(%rsp)
leaq 0x30(%rsp), %rdi
movq %rsp, %rsi
callq 0x40ca
testq %rax, %rax
je 0x394d
leaq 0x30(%rsp), %rdi
movq %rsp, %rsi
callq 0x40e8
movl (%rsp), %ecx
incl %ecx
jmp 0x3669
testb $0x1, 0xc(%rsp)
je 0x35e9
xorl %r15d, %r15d
jmp 0x39b4
callq 0x2040
movl (%rax), %edi
callq 0x20e0
leaq 0x2fb9(%rip), %rsi      # 0x6933
xorl %edi, %edi
movq %rax, %rdx
xorl %eax, %eax
callq 0x26e8
movl %ebx, %edi
callq 0x2390
pushq $-0x2
jmp 0x39e8
callq 0x2040
movl (%rax), %edi
callq 0x20e0
leaq 0x2fdf(%rip), %rsi      # 0x6983
xorl %edi, %edi
movq %rax, %rdx
xorl %eax, %eax
callq 0x26e8
pushq $-0x4
popq %r15
leaq 0x30(%rsp), %rdi
callq 0x3cb8
jmp 0x39ea
callq 0x2040
movl (%rax), %edi
callq 0x20e0
leaq 0x2f76(%rip), %rsi      # 0x6949
xorl %edi, %edi
movq %rax, %rdx
xorl %eax, %eax
callq 0x26e8
movl %ebx, %edi
callq 0x2390
pushq $-0x3
popq %r15
movl %r15d, %eax
addq $0x168, %rsp            # imm = 0x168
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x30b3(%rip), %rsi      # 0x6ab9
xorl %edi, %edi
xorl %eax, %eax
callq 0x26e8
jmp 0x39b4
jmp 0x3a29
jmp 0x3a29
jmp 0x3a29
jmp 0x3a29
jmp 0x3a29
jmp 0x3a29
jmp 0x3a29
jmp 0x3a29
jmp 0x3a29
jmp 0x3a29
jmp 0x3a29
jmp 0x3a29
movq %rax, %rbx
leaq 0x30(%rsp), %rdi
callq 0x3cb8
movq %rbx, %rdi
callq 0x2350