// File: /workspace/github_cpp_makefile_star2_O3/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, %r13d
movl $0x1, 0x24(%rsp)
movl $0x2b48, %edi           # imm = 0x2B48
movl $0x1, %esi
xorl %edx, %edx
callq 0x4795
testl %eax, %eax
js 0x3c61
movl %eax, %ebx
leaq 0x24(%rsp), %rdx
movl $0x5421, %esi           # imm = 0x5421
movl %eax, %edi
xorl %eax, %eax
callq 0x22d0
testl %eax, %eax
js 0x3c7b
movl %ebx, %edi
movl $0x400, %esi            # imm = 0x400
callq 0x2230
testl %eax, %eax
js 0x3cd8
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)
movl $0x1, %eax
movl %ebx, %ecx
shlq %cl, %rax
movaps %xmm0, 0xe0(%rsp)
movl $0x1, %edx
movl %ebx, %ecx
shrl $0x6, %ecx
orq %rax, 0x70(%rsp,%rcx,8)
leal 0x3f(%r13), %eax
testl %r13d, %r13d
cmovnsl %r13d, %eax
movl %eax, %esi
andl $-0x40, %esi
movl %r13d, %ecx
subl %esi, %ecx
shlq %cl, %rdx
sarl $0x6, %eax
cltq
orq %rdx, 0x70(%rsp,%rax,8)
movl %ebx, 0x14(%rsp)
movl %ebx, %r15d
cmpl %r13d, %ebx
jge 0x37b1
movl %r13d, 0x14(%rsp)
movl %r13d, %r15d
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 0x3174(%rip), %rsi      # 0x695e
movl $0x2, %edi
xorl %eax, %eax
callq 0x27f8
leal 0x1(%r15), %ebp
movl $0x10, %ecx
leaq 0xf8(%rsp), %rdi
leaq 0x70(%rsp), %rsi
rep  movsq (%rsi), %es:(%rdi)
movl $0x3, %edi
leaq 0x314e(%rip), %rsi      # 0x6969
xorl %eax, %eax
callq 0x27f8
movl %ebp, %edi
leaq 0xf8(%rsp), %rsi
xorl %edx, %edx
xorl %ecx, %ecx
leaq 0x60(%rsp), %r8
callq 0x21f0
movl %eax, %r12d
testl %eax, %eax
js 0x3ca8
jne 0x385c
movl $0x3, %edi
leaq 0x3146(%rip), %rsi      # 0x6999
xorl %eax, %eax
callq 0x27f8
jmp 0x37fa
movl $0x3, %edi
leaq 0x314b(%rip), %rsi      # 0x69b3
movl %r12d, %edx
xorl %eax, %eax
callq 0x27f8
movl $0x0, 0xc(%rsp)
xorl %edx, %edx
testl %r15d, %r15d
js 0x3c49
movq $0x0, 0x18(%rsp)
leal 0x3f(%rdx), %eax
testl %edx, %edx
cmovnsl %edx, %eax
sarl $0x6, %eax
cltq
movq 0xf8(%rsp,%rax,8), %rax
btq %rdx, %rax
jae 0x3b27
decl %r12d
cmpl %ebx, %edx
jne 0x3a1c
movl $0x3, %edi
leaq 0x30ff(%rip), %rsi      # 0x69c3
xorl %eax, %eax
callq 0x27f8
movl $0xffffffff, 0x10(%rsp) # imm = 0xFFFFFFFF
movl %ebx, %edi
xorl %esi, %esi
xorl %edx, %edx
callq 0x20c0
movl %eax, 0x10(%rsp)
testl %eax, %eax
js 0x3a59
movl $0x3, %edi
leaq 0x30f9(%rip), %rsi      # 0x69ef
movl %eax, %edx
xorl %eax, %eax
callq 0x27f8
movl 0x10(%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 %r15d, %edi
cmovgl %edi, %r15d
movl %r13d, %esi
movq %r14, %rdx
leaq 0x28(%rsp), %rcx
callq 0x2f7f
movl 0x10(%rsp), %ecx
testl %eax, %eax
js 0x394f
cmpl $-0x1, %ecx
jne 0x38d3
jmp 0x3b22
xorl %edi, %edi
leaq 0x30b7(%rip), %rsi      # 0x6a0f
movl %ecx, %edx
xorl %eax, %eax
callq 0x27f8
movl 0x10(%rsp), %edi
callq 0x2380
movl 0x10(%rsp), %ecx
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 %r15d, %ecx
jne 0x39b4
leal 0x3f(%r15), %eax
testl %r15d, %r15d
cmovnsl %r15d, %eax
sarl $0x6, %eax
cltq
movq 0x70(%rsp,%rax,8), %rax
movl %r15d, %edx
decl %r15d
btq %rdx, %rax
jae 0x3990
incl %r15d
movslq %ecx, %rax
movq 0x28(%rsp), %rdi
movq 0x30(%rsp), %r8
xorl %edx, %edx
divq %r8
movq (%rdi,%rdx,8), %rax
testq %rax, %rax
je 0x3945
movq %rdx, %rsi
movq (%rax), %r9
cmpl 0x8(%r9), %ecx
je 0x3a04
movq (%r9), %r9
testq %r9, %r9
je 0x3945
movslq 0x8(%r9), %rdi
movq %rdi, %rax
xorl %edx, %edx
divq %r8
cmpq %rsi, %rdx
jne 0x3945
cmpl %edi, %ecx
jne 0x39df
leaq 0x28(%rsp), %rdi
leaq 0x10(%rsp), %rsi
callq 0x435a
movl 0x10(%rsp), %ecx
jmp 0x3945
cmpl %r13d, %edx
jne 0x3a92
movl $0x3, %edi
leaq 0x3015(%rip), %rsi      # 0x6a42
xorl %eax, %eax
callq 0x27f8
movl 0xc(%rsp), %edi
leaq 0x28(%rsp), %rsi
movq %r14, %rdx
leaq 0x70(%rsp), %rcx
leaq 0x14(%rsp), %r8
callq 0x338e
movl 0x14(%rsp), %r15d
jmp 0x3b27
movl %r15d, 0x14(%rsp)
callq 0x2040
movl (%rax), %edi
cmpl $0xb, %edi
je 0x3b27
callq 0x20e0
movb $0x1, %cl
movq %rcx, 0x18(%rsp)
xorl %edi, %edi
leaq 0x2f5a(%rip), %rsi      # 0x69dd
movq %rax, %rdx
xorl %eax, %eax
callq 0x27f8
jmp 0x3b27
movl $0x3, %edi
leaq 0x2fba(%rip), %rsi      # 0x6a58
xorl %eax, %eax
callq 0x27f8
movl $0xff84, %edx           # imm = 0xFF84
leaq 0x76a6f(%rip), %rbp     # 0x7a520
movq %rbp, %rdi
xorl %esi, %esi
callq 0x2130
movl 0xc(%rsp), %edi
movl $0xff84, %edx           # imm = 0xFF84
movq %rbp, %rsi
xorl %ecx, %ecx
callq 0x20d0
movq %rax, %rbp
testl %ebp, %ebp
js 0x3b49
je 0x3b5e
movl $0x3, %edi
leaq 0x2fae(%rip), %rsi      # 0x6a95
movl %ebp, %edx
leaq 0x76a30(%rip), %rcx     # 0x7a520
xorl %eax, %eax
callq 0x27f8
movl 0xc(%rsp), %esi
andl $0x7fffffff, %ebp       # imm = 0x7FFFFFFF
movl %r13d, %edi
leaq 0x76a15(%rip), %rdx     # 0x7a520
movq %rbp, %rcx
movq %r14, %r8
callq 0x2b26
movq %rax, %rbp
testl %ebp, %ebp
jns 0x3b27
jmp 0x3d17
movl %r15d, 0x14(%rsp)
movl 0xc(%rsp), %eax
leal 0x1(%rax), %edx
movl %edx, 0xc(%rsp)
cmpl %r15d, %eax
jge 0x3c52
testl %r12d, %r12d
jg 0x388e
jmp 0x3c52
callq 0x2040
xorl %edi, %edi
cmpl $0xb, (%rax)
leaq 0x2f0d(%rip), %rsi      # 0x6a67
je 0x3b27
jmp 0x3b6a
movl $0x1, %edi
leaq 0x2f15(%rip), %rsi      # 0x6a7f
movl 0xc(%rsp), %edx
xorl %eax, %eax
callq 0x27f8
movl 0xc(%rsp), %edx
movl $0x1, %edi
leaq 0x2f56(%rip), %rsi      # 0x6adb
xorl %eax, %eax
callq 0x27f8
movl 0xc(%rsp), %edi
callq 0x2380
movslq 0xc(%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 %r15d, %ecx
jne 0x3be5
leal 0x3f(%r15), %eax
testl %r15d, %r15d
cmovnsl %r15d, %eax
sarl $0x6, %eax
cltq
movq 0x70(%rsp,%rax,8), %rax
movl %r15d, %edx
decl %r15d
btq %rdx, %rax
jae 0x3bbc
incl %r15d
movl %r15d, 0x14(%rsp)
movq 0x28(%rsp), %rdi
movq 0x30(%rsp), %r8
movq %rcx, %rax
xorl %edx, %edx
divq %r8
movq (%rdi,%rdx,8), %rax
testq %rax, %rax
je 0x3b27
movq %rdx, %rsi
movq (%rax), %r9
cmpl 0x8(%r9), %ecx
je 0x3c35
movq (%r9), %r9
testq %r9, %r9
je 0x3b27
movslq 0x8(%r9), %rdi
movq %rdi, %rax
xorl %edx, %edx
divq %r8
cmpq %rsi, %rdx
jne 0x3b27
cmpl %edi, %ecx
jne 0x3c10
leaq 0x28(%rsp), %rdi
leaq 0xc(%rsp), %rsi
callq 0x435a
jmp 0x3b27
movq $0x0, 0x18(%rsp)
testb $0x1, 0x18(%rsp)
je 0x37f6
xorl %ebp, %ebp
jmp 0x3ccc
leaq 0x2ca9(%rip), %rsi      # 0x6911
xorl %edi, %edi
xorl %eax, %eax
callq 0x27f8
movl $0xffffffff, %ebp       # imm = 0xFFFFFFFF
jmp 0x3d03
callq 0x2040
movl (%rax), %edi
callq 0x20e0
leaq 0x2ca5(%rip), %rsi      # 0x6933
xorl %edi, %edi
movq %rax, %rdx
xorl %eax, %eax
callq 0x27f8
movl %ebx, %edi
callq 0x2380
movl $0xfffffffe, %ebp       # imm = 0xFFFFFFFE
jmp 0x3d03
callq 0x2040
movl (%rax), %edi
callq 0x20e0
movl $0xfffffffc, %ebp       # imm = 0xFFFFFFFC
leaq 0x2cc3(%rip), %rsi      # 0x6983
xorl %edi, %edi
movq %rax, %rdx
xorl %eax, %eax
callq 0x27f8
leaq 0x28(%rsp), %rdi
callq 0x3fe4
jmp 0x3d03
callq 0x2040
movl (%rax), %edi
callq 0x20e0
leaq 0x2c5e(%rip), %rsi      # 0x6949
xorl %edi, %edi
movq %rax, %rdx
xorl %eax, %eax
callq 0x27f8
movl %ebx, %edi
callq 0x2380
movl $0xfffffffd, %ebp       # imm = 0xFFFFFFFD
movl %ebp, %eax
addq $0x178, %rsp            # imm = 0x178
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x2d9b(%rip), %rsi      # 0x6ab9
xorl %edi, %edi
xorl %eax, %eax
callq 0x27f8
jmp 0x3ccc
jmp 0x3d3d
jmp 0x3d3d
jmp 0x3d3d
jmp 0x3d3d
jmp 0x3d3d
jmp 0x3d3d
jmp 0x3d3d
jmp 0x3d3d
jmp 0x3d3d
jmp 0x3d3d
movq %rax, %rbx
leaq 0x28(%rsp), %rdi
callq 0x3fe4
movq %rbx, %rdi
callq 0x2350