// File: /workspace/github_c_makefile_star2_O2/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 $0x48, %rsp
movq %rsi, %r14
movl %edi, %r15d
leaq 0x3a3a(%rip), %rax      # 0x6004
movq %rax, -0x30(%rbp)
leaq 0x3a3e(%rip), %r12      # 0x6013
leaq 0x75c4(%rip), %r13      # 0x9ba0
leaq -0x4c(%rbp), %rbx
movl %r15d, %edi
movq %r14, %rsi
movq %r12, %rdx
movq %r13, %rcx
movq %rbx, %r8
callq 0x2160
testl %eax, %eax
je 0x25e0
cmpl $-0x1, %eax
je 0x2646
cmpl $0x3a, %eax
je 0x262f
cmpl $0x3f, %eax
je 0x262f
cmpl $0x63, %eax
jne 0x261c
movq 0x79bd(%rip), %rax      # 0x9fd0
movq (%rax), %rax
movq %rax, -0x30(%rbp)
jmp 0x25e0
cmpl $0x68, %eax
je 0x262f
cmpl $0x74, %eax
je 0x26a0
cmpl $0x56, %eax
je 0x2910
callq 0x29b3
pushq $0x1
popq %rax
addq $0x48, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq -0x30(%rbp), %rdi
callq 0x29e0
testq %rax, %rax
je 0x26ab
movq %rax, %rbx
leaq 0x39c9(%rip), %rsi      # 0x6027
leaq 0x39d5(%rip), %rdx      # 0x603a
leaq 0x39ef(%rip), %r8       # 0x605b
pushq $0x2
popq %rdi
pushq $0x5d
popq %rcx
xorl %eax, %eax
callq 0x4c60
xorl %eax, %eax
callq 0x47d0
leaq 0x39a0(%rip), %rsi      # 0x6027
leaq 0x39ac(%rip), %rdx      # 0x603a
testl %eax, %eax
je 0x26d2
leaq 0x39ea(%rip), %r8       # 0x6083
pushq $0x4
popq %rdi
pushq $0x61
jmp 0x26c5
movq -0x30(%rbp), %rdi
callq 0x29e0
jmp 0x2634
leaq 0x3975(%rip), %rsi      # 0x6027
leaq 0x3981(%rip), %rdx      # 0x603a
leaq 0x397f(%rip), %r8       # 0x603f
pushq $0x4
popq %rdi
pushq $0x59
popq %rcx
xorl %eax, %eax
callq 0x4c60
jmp 0x2634
leaq 0x39bd(%rip), %r8       # 0x6096
pushq $0x2
popq %rdi
pushq $0x65
popq %rcx
xorl %eax, %eax
callq 0x4c60
xorl %edi, %edi
callq 0x30d4
testq %rax, %rax
je 0x28f1
movq %rax, %r14
movzwl 0x210(%rbx), %edi
callq 0x341e
testl %eax, %eax
js 0x2931
movl %eax, %r15d
movl %eax, %edi
callq 0x5c34
movl %r15d, %edi
movq %r14, %rsi
xorl %edx, %edx
callq 0x4581
testq %rax, %rax
je 0x2972
leaq -0x68(%rbp), %rdx
movq %rax, 0x4(%rdx)
movl $0x80000001, (%rdx)     # imm = 0x80000001
movq %r14, %rdi
movl %r15d, %esi
callq 0x31a3
movl (%rbx), %edi
movl 0x4(%rbx), %esi
callq 0x5720
movq %rax, -0x40(%rbp)
testq %rax, %rax
je 0x2991
leaq -0x38(%rbp), %rax
movl $0x10, (%rax)
leaq 0x38b9(%rip), %rsi      # 0x6027
leaq 0x38c5(%rip), %r13      # 0x603a
leaq 0x399c(%rip), %r8       # 0x6118
pushq $0x2
popq %r12
movl %r12d, %edi
movq %r13, %rdx
movl $0x89, %ecx
xorl %eax, %eax
callq 0x4c60
leaq 0x39a7(%rip), %r8       # 0x6140
movl %r12d, %edi
leaq 0x3884(%rip), %rsi      # 0x6027
movq %r13, %rdx
movl $0x8b, %ecx
xorl %eax, %eax
callq 0x4c60
movq %rbx, -0x48(%rbp)
movq %r14, -0x30(%rbp)
xorl %eax, %eax
callq 0x4877
movq %r14, %rdi
movl $0x400, %esi            # imm = 0x400
movl %eax, %edx
callq 0x32cc
testl %eax, %eax
js 0x2950
movl %eax, %r12d
xorl %eax, %eax
callq 0x48e7
movl %r12d, -0x34(%rbp)
movslq %r12d, %rbx
imulq $0xc, %rbx, %r14
addq $-0x8, %r14
xorl %r12d, %r12d
cmpq %r12, %rbx
je 0x28e8
movq -0x30(%rbp), %rax
movq 0x8(%rax), %rax
movq (%rax,%r14), %rdx
cmpl %r15d, (%rdx)
je 0x2830
movl -0x4(%rax,%r14), %eax
andl $0x19, %eax
cmpl $0x1, %eax
je 0x28cc
movl %r13d, %edi
callq 0x21d0
incq %r12
addq $-0xc, %r14
jmp 0x27f4
movq -0x48(%rbp), %rbx
movq -0x30(%rbp), %r14
movl %r15d, %edi
leaq -0x5c(%rbp), %rsi
leaq -0x38(%rbp), %rdx
callq 0x23b0
movl %eax, %r13d
testl %eax, %eax
js 0x289c
movl -0x58(%rbp), %edi
callq 0x2100
movzwl -0x5a(%rbp), %ecx
rolw $0x8, %cx
movzwl %cx, %ecx
movl %ecx, (%rsp)
pushq $0x2
popq %rdi
leaq 0x37b8(%rip), %rsi      # 0x6027
leaq 0x37c4(%rip), %rdx      # 0x603a
movl $0xa9, %ecx
leaq 0x38f5(%rip), %r8       # 0x6177
movq %rax, %r9
xorl %eax, %eax
callq 0x4c60
movl %r13d, %edi
movq %r14, %rsi
movq %rbx, %rdx
callq 0x3348
jmp 0x2838
callq 0x2050
cmpl $0xb, (%rax)
je 0x28dc
pushq $0x4
popq %rdi
leaq 0x3777(%rip), %rsi      # 0x6027
leaq 0x3783(%rip), %rdx      # 0x603a
movl $0xa2, %ecx
leaq 0x38a6(%rip), %r8       # 0x6169
xorl %eax, %eax
callq 0x4c60
jmp 0x28dc
movq -0x40(%rbp), %rdi
leaq 0xc3f(%rip), %rsi       # 0x3516
callq 0x59f3
notl %r12d
addl -0x34(%rbp), %r12d
jmp 0x27e2
movq -0x30(%rbp), %r14
jmp 0x27ba
leaq 0x372f(%rip), %rsi      # 0x6027
leaq 0x373b(%rip), %rdx      # 0x603a
leaq 0x37b2(%rip), %r8       # 0x60b8
pushq $0x4
popq %rdi
pushq $0x69
jmp 0x26c5
movq 0x76d9(%rip), %rax      # 0x9ff0
movq (%rax), %rcx
leaq 0x36f9(%rip), %rdi      # 0x601a
pushq $0xc
popq %rsi
pushq $0x1
popq %rdx
callq 0x2400
jmp 0x2634
leaq 0x36ef(%rip), %rsi      # 0x6027
leaq 0x36fb(%rip), %rdx      # 0x603a
leaq 0x378a(%rip), %r8       # 0x60d0
pushq $0x4
popq %rdi
pushq $0x6f
jmp 0x26c5
leaq 0x36d0(%rip), %rsi      # 0x6027
leaq 0x36dc(%rip), %rdx      # 0x603a
leaq 0x37f1(%rip), %r8       # 0x6156
pushq $0x4
popq %rdi
movl $0x93, %ecx
jmp 0x26c6
leaq 0x36ae(%rip), %rsi      # 0x6027
leaq 0x36ba(%rip), %rdx      # 0x603a
leaq 0x3761(%rip), %r8       # 0x60e8
pushq $0x4
popq %rdi
pushq $0x78
jmp 0x26c5
leaq 0x368f(%rip), %rsi      # 0x6027
leaq 0x369b(%rip), %rdx      # 0x603a
leaq 0x3757(%rip), %r8       # 0x60fd
pushq $0x4
popq %rdi
movl $0x83, %ecx
jmp 0x26c6