// File: /workspace/github_c_makefile_star2_O1/ttoobne[P]bohttpd/src/core/bohttpd.c
// Function: main
int main(int argc, char* argv[]) {
    config_t*           config;
    char*               conf_path;
    struct sockaddr_in  cliaddr;
    socklen_t           cliadrlen;
    epoll_t*            epoll;
    struct epoll_event  epev;
    http_request_t*     event;
    threadpool_t*       threadpool;
    msec_t              timeout;
    int                 opt;
    int                 options_index;
    int                 listenfd;
    int                 connfd;
    int                 evnum;

    /* 配置文件默认路径 */
    conf_path = CONF_PATH;

    /* 解析参数 */
    while ((opt = getopt_long(argc, argv, "c:Vt?h", long_options, &options_index)) != EOF) {
        switch (opt) {
            case  0 : break;
            case 'c':
                conf_path = optarg;
                break;
            case 'V':
                fprintf(stderr, BOHTTPD_VER"\n");
                return 1;
            case 't':
                parse_configuration(conf_path);
                return 1;
            case ':':
            case '?':
            case 'h':
                usage();
                return 1;
            default:
                usage();
                return 1;
        }
    }

    /* 解析配置文件 */
    if ((config = parse_configuration(conf_path)) == NULL) {
        log_error("parse configuration failed.");
        return 1;
    }

    log_info("configuration file parsing is complete.");

    /* 初始化定时器 */
    if (init_timer() != 0) {
        log_error("init timer failed.");
        return 1;
    }

    log_info("timer initialization is complete.");

    /* 创建 epoll 文件描述符 */
    if ((epoll = epoll_create_fd(0)) == NULL) {
        log_error("create epoll fd failed.");
        return 1;
    }

    /* 创建监听描述符 */
    if ((listenfd = create_listenfd(config->port)) < 0) {
        log_error("create listenfd failed.");
        return 1;
    }

    /* 将监听描述符设置为非阻塞 */
    set_nonblocking(listenfd);

    /* 为了将 listenfd 放入 epoll 中，需要额外为 listenfd 初始化一个事件结构体  */
    if ((event = http_request_init(listenfd, epoll, NULL)) == NULL) {
        log_error("event_t init failed.");
        return 1;
    }

    /* epoll 监听 listenfd 上的 accept 事件，边缘触发 */
    epev.data.ptr = (void*)event;
    epev.events = EPOLLIN | EPOLLET;
    epoll_add_fd(epoll, listenfd, &epev);

    /* 创建线程池，大小从配置文件读取 */
    if ((threadpool = threadpool_create(config->threadpool, config->taskqueue)) == NULL) {
        log_error("thread poll create failed.");
        return 1;
    }

    cliadrlen = sizeof(cliaddr);    /* 必须初始化 */

    log_info("thread pool initialization is complete.");

    log_info("Bohttpd goes to work.");

    /* 主循环 */
    for ( ;; ) {
        timeout = find_timer();

        /* 根据超时时间最接近的事件确定 epoll wait 的阻塞时间 */
        if ((evnum = epoll_wait_event(epoll, MAX_EVENTS, timeout)) < 0) {
            log_error("epoll wait failed.");
            return 1;
        }

        /* 此时一定有超时事件，需要执行回调函数 */
        expire_timers();

        while(evnum -- ) {
            event = (http_request_t*)(epoll->events[evnum].data.ptr);
            if (event->fd == listenfd) {
                /* 边缘触发，所以必须处理完所有的连接请求 */
                for ( ;; ) {
                    //log_debug("ready to accept");
                    if ((connfd = accept(listenfd, (struct sockaddr*)&cliaddr, &cliadrlen)) < 0) {
                        if (errno != EAGAIN && errno != EWOULDBLOCK) {
                            log_error("accept error.");
                        }

                        break;
                    }

                    log_info("new connection arrive. client<%s:%u>", 
                            inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port));
                    
                    /* 初始化已连接描述符，加入定时器、epoll 监听可读事件 */
                    http_init_connection(connfd, epoll, config);
                }
                
            } else {
                if ((epoll->events[evnum].events & EPOLLERR) || 
                    (epoll->events[evnum].events & EPOLLHUP) || /* 对端关闭连接 */
                    !(epoll->events[evnum].events & EPOLLIN)) {

                    close(connfd);
                    continue;
                }

                event = epoll->events[evnum].data.ptr;

                /* 将执行任务添加至工作队列等待线程执行 */
                threadpool_add_task(threadpool, execute_request, (void*)event);

                //execute_request(event);
            }
        }
    }

    config_destroy(config);

    epoll_free(epoll);

    threadpool_destroy(threadpool);

    return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x58, %rsp
movq %rsi, %r14
movl %edi, %r15d
leaq 0x487a(%rip), %rax      # 0x7004
movq %rax, -0x30(%rbp)
leaq 0x487e(%rip), %r12      # 0x7013
leaq 0x8404(%rip), %r13      # 0xaba0
leaq -0x64(%rbp), %rbx
movl %r15d, %edi
movq %r14, %rsi
movq %r12, %rdx
movq %r13, %rcx
movq %rbx, %r8
callq 0x2160
testl %eax, %eax
je 0x27a0
cmpl $0x62, %eax
jle 0x27d6
cmpl $0x63, %eax
jne 0x284b
movq 0x8803(%rip), %rax      # 0xafd0
movq (%rax), %rax
movq %rax, -0x30(%rbp)
jmp 0x27a0
cmpl $0x39, %eax
jg 0x2b50
cmpl $-0x1, %eax
jne 0x2b9c
movq -0x30(%rbp), %rdi
callq 0x2c14
testq %rax, %rax
je 0x285f
movq %rax, %r14
leaq 0x4827(%rip), %rsi      # 0x7027
leaq 0x4833(%rip), %rdx      # 0x703a
leaq 0x484d(%rip), %r8       # 0x705b
movl $0x2, %edi
movl $0x5d, %ecx
xorl %eax, %eax
callq 0x252a
xorl %eax, %eax
callq 0x4b8c
leaq 0x47fa(%rip), %rsi      # 0x7027
leaq 0x4806(%rip), %rdx      # 0x703a
testl %eax, %eax
je 0x2899
leaq 0x4844(%rip), %r8       # 0x7083
movl $0x4, %edi
movl $0x61, %ecx
jmp 0x287e
cmpl $0x74, %eax
jne 0x2b69
movq -0x30(%rbp), %rdi
callq 0x2c14
jmp 0x2885
leaq 0x47c1(%rip), %rsi      # 0x7027
leaq 0x47cd(%rip), %rdx      # 0x703a
leaq 0x47cb(%rip), %r8       # 0x703f
movl $0x4, %edi
movl $0x59, %ecx
xorl %eax, %eax
callq 0x252a
movl $0x1, %eax
addq $0x58, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x47f6(%rip), %r8       # 0x7096
movl $0x2, %edi
movl $0x65, %ecx
xorl %eax, %eax
callq 0x252a
xorl %edi, %edi
callq 0x3324
testq %rax, %rax
je 0x2b78
movq %rax, %rbx
movzwl 0x210(%r14), %edi
callq 0x36c2
testl %eax, %eax
js 0x2ba6
movl %eax, %r15d
movl %eax, %edi
callq 0x5fc0
movl %r15d, %edi
movq %rbx, %rsi
xorl %edx, %edx
callq 0x490b
testq %rax, %rax
je 0x2bca
leaq -0x70(%rbp), %rdx
movq %rax, 0x4(%rdx)
movl $0x80000001, (%rdx)     # imm = 0x80000001
movq %rbx, %rdi
movl %r15d, %esi
callq 0x340b
movl (%r14), %edi
movl 0x4(%r14), %esi
callq 0x5a4c
movq %rax, -0x58(%rbp)
testq %rax, %rax
je 0x2bee
movl $0x10, -0x3c(%rbp)
leaq 0x46ee(%rip), %r12      # 0x7027
movq %rbx, -0x30(%rbp)
leaq 0x46f6(%rip), %r13      # 0x703a
leaq 0x47cd(%rip), %r8       # 0x7118
movl $0x2, %edi
movq %r12, %rsi
movq %r13, %rdx
movl $0x89, %ecx
xorl %eax, %eax
callq 0x252a
leaq 0x47d7(%rip), %r8       # 0x7140
movl $0x2, %edi
movq %r12, %rsi
movq %r13, %rdx
movq -0x30(%rbp), %rbx
movl $0x8b, %ecx
xorl %eax, %eax
callq 0x252a
xorl %eax, %eax
callq 0x4c43
movq %rbx, %rdi
movl $0x400, %esi            # imm = 0x400
movl %eax, %edx
callq 0x355b
testl %eax, %eax
js 0x2b2c
movl %eax, %r13d
movq %r14, -0x60(%rbp)
movl %r15d, -0x38(%rbp)
xorl %eax, %eax
callq 0x4cb7
testl %r13d, %r13d
je 0x2b0b
leaq -0x4c(%rbp), %rcx
movl %r13d, -0x34(%rbp)
movslq %r13d, %r13
leaq (,%r13,2), %rax
addq %r13, %rax
leaq -0x8(,%rax,4), %r14
xorl %ebx, %ebx
movq -0x30(%rbp), %rax
movq 0x8(%rax), %rax
movq (%rax,%r14), %rdx
cmpl %r15d, (%rdx)
je 0x2a1c
movl -0x4(%rax,%r14), %eax
andl $0x19, %eax
cmpl $0x1, %eax
je 0x2ada
movl %r12d, %edi
callq 0x21d0
incq %rbx
addq $-0xc, %r14
cmpq %rbx, %r13
leaq -0x4c(%rbp), %rcx
jne 0x29dd
jmp 0x2b07
movl %r15d, %edi
movq %rcx, %rsi
leaq -0x3c(%rbp), %rdx
callq 0x23b0
movl %eax, %r12d
testl %eax, %eax
movq -0x30(%rbp), %r13
leaq 0x45ff(%rip), %r15      # 0x703a
leaq 0x4735(%rip), %r14      # 0x7177
js 0x2aa1
movl -0x48(%rbp), %edi
callq 0x2100
movzwl -0x4a(%rbp), %ecx
rolw $0x8, %cx
movzwl %cx, %ecx
movl %ecx, (%rsp)
movl $0x2, %edi
leaq 0x45c1(%rip), %rsi      # 0x7027
movq %r15, %rdx
movl $0xa9, %ecx
movq %r14, %r8
movq %rax, %r9
xorl %eax, %eax
callq 0x252a
movl %r12d, %edi
movq %r13, %rsi
movq -0x60(%rbp), %rdx
callq 0x35e4
movl -0x38(%rbp), %edi
leaq -0x4c(%rbp), %rsi
leaq -0x3c(%rbp), %rdx
callq 0x23b0
movl %eax, %r12d
testl %eax, %eax
jns 0x2a44
movq %r13, %r14
movl -0x38(%rbp), %r15d
callq 0x2050
cmpl $0xb, (%rax)
je 0x2aee
movl $0x4, %edi
leaq 0x4569(%rip), %rsi      # 0x7027
leaq 0x4575(%rip), %rdx      # 0x703a
movl $0xa2, %ecx
leaq 0x4698(%rip), %r8       # 0x7169
xorl %eax, %eax
callq 0x252a
jmp 0x2aee
movq -0x58(%rbp), %rdi
leaq 0xd06(%rip), %rsi       # 0x37eb
callq 0x5d5b
movq -0x30(%rbp), %r14
leaq -0x4c(%rbp), %rcx
movl -0x34(%rbp), %r13d
decl %r13d
subl %ebx, %r13d
movq %r14, %rbx
jne 0x29c1
jmp 0x2b0b
movq -0x30(%rbp), %rbx
xorl %eax, %eax
callq 0x4c43
movq %rbx, %rdi
movl $0x400, %esi            # imm = 0x400
movl %eax, %edx
callq 0x355b
movl %eax, %r13d
testl %eax, %eax
jns 0x29ad
leaq 0x44f4(%rip), %rsi      # 0x7027
leaq 0x4500(%rip), %rdx      # 0x703a
leaq 0x4615(%rip), %r8       # 0x7156
movl $0x4, %edi
movl $0x93, %ecx
jmp 0x287e
cmpl $0x3a, %eax
je 0x2b6e
cmpl $0x3f, %eax
je 0x2b6e
cmpl $0x56, %eax
jne 0x2b9c
callq 0x24e4
jmp 0x2885
cmpl $0x68, %eax
jne 0x2b9c
callq 0x24c0
jmp 0x2885
leaq 0x44a8(%rip), %rsi      # 0x7027
leaq 0x44b4(%rip), %rdx      # 0x703a
leaq 0x452b(%rip), %r8       # 0x70b8
movl $0x4, %edi
movl $0x69, %ecx
jmp 0x287e
callq 0x2506
jmp 0x2885
leaq 0x447a(%rip), %rsi      # 0x7027
leaq 0x4486(%rip), %rdx      # 0x703a
leaq 0x4515(%rip), %r8       # 0x70d0
movl $0x4, %edi
movl $0x6f, %ecx
jmp 0x287e
leaq 0x4456(%rip), %rsi      # 0x7027
leaq 0x4462(%rip), %rdx      # 0x703a
leaq 0x4509(%rip), %r8       # 0x70e8
movl $0x4, %edi
movl $0x78, %ecx
jmp 0x287e
leaq 0x4432(%rip), %rsi      # 0x7027
leaq 0x443e(%rip), %rdx      # 0x703a
leaq 0x44fa(%rip), %r8       # 0x70fd
movl $0x4, %edi
movl $0x83, %ecx
jmp 0x287e
nop