// File: /workspace/github_cpp_makefile_star2_O1/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 $0x178, %rsp            # imm = 0x178
movq %rsi, %r14
movl %edi, %r15d
movl $0x1, 0x14(%rsp)
movl $0x2b48, %edi           # imm = 0x2B48
movl $0x1, %esi
xorl %edx, %edx
callq 0x4931
testl %eax, %eax
js 0x3e22
movl %eax, %ebx
leaq 0x14(%rsp), %rdx
movl $0x5421, %esi           # imm = 0x5421
movl %eax, %edi
xorl %eax, %eax
callq 0x22d0
testl %eax, %eax
js 0x3e3c
movl %ebx, %edi
movl $0x400, %esi            # imm = 0x400
callq 0x2230
testl %eax, %eax
js 0x3e69
xorps %xmm0, %xmm0
movaps %xmm0, 0x70(%rsp)
movaps %xmm0, 0x80(%rsp)
movaps %xmm0, 0x90(%rsp)
movaps %xmm0, 0xa0(%rsp)
movaps %xmm0, 0xb0(%rsp)
movaps %xmm0, 0xc0(%rsp)
movaps %xmm0, 0xd0(%rsp)
movaps %xmm0, 0xe0(%rsp)
movl $0x1, %eax
movl $0x1, %edx
movl %ebx, %ecx
shlq %cl, %rdx
movl %ebx, %ecx
shrl $0x6, %ecx
orq %rdx, 0x70(%rsp,%rcx,8)
leal 0x3f(%r15), %edx
testl %r15d, %r15d
cmovnsl %r15d, %edx
movl %edx, %esi
andl $-0x40, %esi
movl %r15d, %ecx
subl %esi, %ecx
shlq %cl, %rax
movl %ebx, (%rsp)
sarl $0x6, %edx
movslq %edx, %rcx
orq %rax, 0x70(%rsp,%rcx,8)
cmpl %r15d, %ebx
jge 0x38d0
movl %r15d, (%rsp)
movq $0xb4, 0x60(%rsp)
movq $0x0, 0x68(%rsp)
leaq 0x58(%rsp), %rax
movq %rax, -0x30(%rax)
movq $0x1, -0x28(%rax)
movups %xmm0, -0x20(%rax)
movl $0x3f800000, -0x10(%rax) # imm = 0x3F800000
movups %xmm0, -0x8(%rax)
leaq 0x4055(%rip), %rsi      # 0x795e
movl $0x2, %edi
xorl %eax, %eax
callq 0x27f8
leaq 0xf8(%rsp), %r12
leaq 0x409f(%rip), %rbp      # 0x79c3
movq $0x0, 0x18(%rsp)
movq %r14, 0x20(%rsp)
movl $0x10, %ecx
movq %r12, %rdi
leaq 0x70(%rsp), %rsi
rep  movsq (%rsi), %es:(%rdi)
movl $0x3, %edi
leaq 0x401b(%rip), %rsi      # 0x7969
xorl %eax, %eax
callq 0x27f8
movl (%rsp), %edi
incl %edi
movq %r12, %rsi
xorl %edx, %edx
xorl %ecx, %ecx
leaq 0x60(%rsp), %r8
callq 0x21f0
testl %eax, %eax
js 0x3e96
je 0x3df7
movl $0x3, %edi
leaq 0x402e(%rip), %rsi      # 0x79b3
movl %eax, 0x10(%rsp)
movl %eax, %edx
xorl %eax, %eax
callq 0x27f8
movl $0x0, 0x4(%rsp)
movl (%rsp), %r12d
movl %r12d, %r13d
shrl $0x1f, %r13d
testl %r12d, %r12d
js 0x3de4
xorl %edx, %edx
leal 0x3f(%rdx), %eax
testl %edx, %edx
cmovnsl %edx, %eax
sarl $0x6, %eax
cltq
movq 0xf8(%rsp,%rax,8), %rax
btq %rdx, %rax
jae 0x3db9
decl 0x10(%rsp)
cmpl %ebx, %edx
jne 0x3b5b
movl $0x3, %edi
movq %rbp, %rsi
xorl %eax, %eax
callq 0x27f8
movl $0xffffffff, 0x8(%rsp)  # imm = 0xFFFFFFFF
movl (%rsp), %r12d
movl %ebx, %edi
xorl %esi, %esi
xorl %edx, %edx
callq 0x20c0
movl %eax, 0x8(%rsp)
testl %eax, %eax
js 0x3b91
movl $0x3, %edi
leaq 0x3fd6(%rip), %rsi      # 0x79ef
movl %eax, %edx
xorl %eax, %eax
callq 0x27f8
movl 0x8(%rsp), %edi
leal 0x3f(%rdi), %eax
testl %edi, %edi
cmovnsl %edi, %eax
movl %eax, %edx
andl $-0x40, %edx
movl %edi, %ecx
subl %edx, %ecx
movl $0x1, %edx
shlq %cl, %rdx
sarl $0x6, %eax
cltq
orq %rdx, 0x70(%rsp,%rax,8)
cmpl %r12d, %edi
cmovgl %edi, %r12d
movl %r15d, %esi
movq %r14, %rdx
leaq 0x28(%rsp), %rcx
callq 0x2f56
testl %eax, %eax
js 0x3a70
cmpl $-0x1, 0x8(%rsp)
jne 0x39f6
jmp 0x3c7d
movl 0x8(%rsp), %edx
xorl %edi, %edi
leaq 0x3f92(%rip), %rsi      # 0x7a0f
xorl %eax, %eax
callq 0x27f8
movl 0x8(%rsp), %edi
callq 0x2380
movslq 0x8(%rsp), %rcx
movq $-0x2, %rax
rolq %cl, %rax
leal 0x3f(%rcx), %edx
testl %ecx, %ecx
cmovnsl %ecx, %edx
sarl $0x6, %edx
movslq %edx, %rdx
andq %rax, 0x70(%rsp,%rdx,8)
cmpl %r12d, %ecx
jne 0x3ad9
leal 0x3f(%r12), %eax
testl %r12d, %r12d
cmovnsl %r12d, %eax
sarl $0x6, %eax
cltq
movq 0x70(%rsp,%rax,8), %rax
movl %r12d, %edx
decl %r12d
btq %rdx, %rax
jae 0x3ab4
incl %r12d
movq 0x28(%rsp), %rdi
movq 0x30(%rsp), %r8
movq %rcx, %rax
xorl %edx, %edx
divq %r8
movq %rdx, %rsi
movq (%rdi,%rdx,8), %rdx
movl $0x0, %eax
testq %rdx, %rdx
je 0x3b34
movq (%rdx), %r9
movq %rdx, %rax
cmpl 0x8(%r9), %ecx
je 0x3b34
movq %r9, %r10
movq (%r9), %r9
testq %r9, %r9
je 0x3b32
movslq 0x8(%r9), %rdi
movq %rdi, %rax
xorl %edx, %edx
divq %r8
movl $0x0, %eax
cmpq %rsi, %rdx
jne 0x3b34
movq %r10, %rax
cmpl %edi, %ecx
jne 0x3b08
jmp 0x3b34
xorl %eax, %eax
testq %rax, %rax
je 0x3a64
cmpq $0x0, (%rax)
je 0x3a64
leaq 0x28(%rsp), %rdi
leaq 0x8(%rsp), %rsi
callq 0x44e6
jmp 0x3a64
cmpl %r15d, %edx
jne 0x3bc9
movl $0x3, %edi
leaq 0x3ed6(%rip), %rsi      # 0x7a42
xorl %eax, %eax
callq 0x27f8
movl 0x4(%rsp), %edi
leaq 0x28(%rsp), %rsi
movq %r14, %rdx
leaq 0x70(%rsp), %rcx
movq %rsp, %r8
callq 0x339d
jmp 0x3db9
movl %r12d, (%rsp)
callq 0x2040
movl (%rax), %edi
cmpl $0xb, %edi
je 0x3db9
callq 0x20e0
movb $0x1, %cl
movq %rcx, 0x18(%rsp)
xorl %edi, %edi
leaq 0x3e23(%rip), %rsi      # 0x79dd
movq %rax, %rdx
xorl %eax, %eax
callq 0x27f8
jmp 0x3db9
movl $0x3, %edi
leaq 0x3e83(%rip), %rsi      # 0x7a58
xorl %eax, %eax
callq 0x27f8
movl $0xff84, %edx           # imm = 0xFF84
leaq 0x77938(%rip), %r14     # 0x7b520
movq %r14, %rdi
xorl %esi, %esi
callq 0x2130
movl 0x4(%rsp), %edi
movl $0xff84, %edx           # imm = 0xFF84
movq %r14, %rsi
xorl %ecx, %ecx
callq 0x20d0
movq %rax, %rbp
testl %ebp, %ebp
js 0x3c86
je 0x3ca1
movl $0x3, %edi
leaq 0x3e77(%rip), %rsi      # 0x7a95
movl %ebp, %edx
leaq 0x778f9(%rip), %rcx     # 0x7b520
xorl %eax, %eax
callq 0x27f8
movl 0x4(%rsp), %esi
andl $0x7fffffff, %ebp       # imm = 0x7FFFFFFF
movl %r15d, %edi
leaq 0x778de(%rip), %rdx     # 0x7b520
movq %rbp, %rcx
movq 0x20(%rsp), %r8
callq 0x2b25
movq %rax, %rbp
testl %ebp, %ebp
jns 0x3c6c
xorl %edi, %edi
leaq 0x3e5a(%rip), %rsi      # 0x7ab9
xorl %eax, %eax
callq 0x27f8
movl %ebp, %eax
movl %ebp, 0xc(%rsp)
xorl %r14d, %r14d
testl %ebp, %ebp
movl $0x0, %ebp
jns 0x3cbb
jmp 0x3da8
movl %r12d, (%rsp)
jmp 0x3db9
callq 0x2040
xorl %r14d, %r14d
cmpl $0xb, (%rax)
movl $0x0, %edi
leaq 0x3dca(%rip), %rsi      # 0x7a67
jne 0x3cad
jmp 0x3cbb
movl $0x1, %edi
leaq 0x3dd2(%rip), %rsi      # 0x7a7f
movb $0x1, %r14b
movl 0x4(%rsp), %edx
xorl %eax, %eax
callq 0x27f8
movb $0x1, %bpl
testb %r14b, %r14b
je 0x3da8
movl 0x4(%rsp), %edx
movl $0x1, %edi
leaq 0x3e04(%rip), %rsi      # 0x7adb
xorl %eax, %eax
callq 0x27f8
movl 0x4(%rsp), %edi
callq 0x2380
movslq 0x4(%rsp), %rcx
movq $-0x2, %rax
rolq %cl, %rax
leal 0x3f(%rcx), %edx
testl %ecx, %ecx
cmovnsl %ecx, %edx
sarl $0x6, %edx
movslq %edx, %rdx
andq %rax, 0x70(%rsp,%rdx,8)
cmpl %r12d, %ecx
jne 0x3d33
movl (%rsp), %eax
leal 0x3f(%rax), %edx
testl %eax, %eax
cmovnsl %eax, %edx
sarl $0x6, %edx
movslq %edx, %rdx
movq 0x70(%rsp,%rdx,8), %rdx
movl %eax, %esi
decl %eax
btq %rsi, %rdx
jae 0x3d11
incl %eax
movl %eax, (%rsp)
movq 0x28(%rsp), %rdi
movq 0x30(%rsp), %r8
movq %rcx, %rax
xorl %edx, %edx
divq %r8
movq %rdx, %rsi
movq (%rdi,%rdx,8), %rdx
movl $0x0, %eax
testq %rdx, %rdx
je 0x3d8e
movq (%rdx), %r9
movq %rdx, %rax
cmpl 0x8(%r9), %ecx
je 0x3d8e
movq %r9, %r10
movq (%r9), %r9
testq %r9, %r9
je 0x3d8c
movslq 0x8(%r9), %rdi
movq %rdi, %rax
xorl %edx, %edx
divq %r8
movl $0x0, %eax
cmpq %rsi, %rdx
jne 0x3d8e
movq %r10, %rax
cmpl %edi, %ecx
jne 0x3d62
jmp 0x3d8e
xorl %eax, %eax
testq %rax, %rax
je 0x3da8
cmpq $0x0, (%rax)
je 0x3da8
leaq 0x28(%rsp), %rdi
leaq 0x4(%rsp), %rsi
callq 0x44e6
testb %bpl, %bpl
movq 0x20(%rsp), %r14
leaq 0x3c0c(%rip), %rbp      # 0x79c3
je 0x3de4
movl 0x4(%rsp), %eax
leal 0x1(%rax), %edx
movl %edx, 0x4(%rsp)
movl (%rsp), %r12d
cmpl %r12d, %eax
setge %al
cmpl $0x0, 0x10(%rsp)
setle %r13b
orb %al, %r13b
cmpb $0x1, %r13b
jne 0x39b0
testb $0x1, %r13b
leaq 0xf8(%rsp), %r12
jne 0x3e0a
jmp 0x3ebd
movl $0x3, %edi
leaq 0x3b96(%rip), %rsi      # 0x7999
xorl %eax, %eax
callq 0x27f8
testb $0x1, 0x18(%rsp)
je 0x3932
movl $0x0, 0xc(%rsp)
jmp 0x3ebd
leaq 0x3ae8(%rip), %rsi      # 0x7911
xorl %edi, %edi
xorl %eax, %eax
callq 0x27f8
movl $0xffffffff, %eax       # imm = 0xFFFFFFFF
jmp 0x3ecb
callq 0x2040
movl (%rax), %edi
callq 0x20e0
leaq 0x3ae4(%rip), %rsi      # 0x7933
xorl %edi, %edi
movq %rax, %rdx
xorl %eax, %eax
callq 0x27f8
movl %ebx, %edi
callq 0x2380
movl $0xfffffffe, %eax       # imm = 0xFFFFFFFE
jmp 0x3ecb
callq 0x2040
movl (%rax), %edi
callq 0x20e0
leaq 0x3acd(%rip), %rsi      # 0x7949
xorl %edi, %edi
movq %rax, %rdx
xorl %eax, %eax
callq 0x27f8
movl %ebx, %edi
callq 0x2380
movl $0xfffffffd, %eax       # imm = 0xFFFFFFFD
jmp 0x3ecb
callq 0x2040
movl (%rax), %edi
callq 0x20e0
movl $0xfffffffc, 0xc(%rsp)  # imm = 0xFFFFFFFC
leaq 0x3ad2(%rip), %rsi      # 0x7983
xorl %edi, %edi
movq %rax, %rdx
xorl %eax, %eax
callq 0x27f8
leaq 0x28(%rsp), %rdi
callq 0x4198
movl 0xc(%rsp), %eax
addq $0x178, %rsp            # imm = 0x178
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x3eed
jmp 0x3eed
jmp 0x3eed
jmp 0x3eed
jmp 0x3eed
jmp 0x3eed
jmp 0x3eed
jmp 0x3eed
movq %rax, %rbx
jmp 0x3ef9
movq %rax, %rbx
movl %r12d, (%rsp)
leaq 0x28(%rsp), %rdi
callq 0x4198
movq %rbx, %rdi
callq 0x2350