// File: /workspace/github_cpp_makefile_star2_O3/davidgfnet[P]tadns/tadns-server.cc
// Function: main
int main(int argc, char *argv[]) {
    int port = 53;

    DNSResolverIface *dns;
    if ((dns = createResolver(NULL, 10)) == NULL) {
        (void) fprintf(stderr, "failed to init resolver\n");
        exit(EXIT_FAILURE);
    }

    // Bind port!
    struct sockaddr_in servaddr;
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(port);

    listenfd = socket(AF_INET, SOCK_DGRAM, 0);
    int yes = 1;
    setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
    if (bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) {
        printf("Error %u binding the port.\n", errno); perror("bind");
        exit(EXIT_FAILURE);
    }

    int epollfd = epoll_create(1);
    auto dnsfds = dns->getFds();

    struct epoll_event ev;
    ev.events = POLLIN;
    ev.data.ptr = NULL;

    epoll_ctl(epollfd, EPOLL_CTL_ADD, dnsfds.first,  &ev);
    epoll_ctl(epollfd, EPOLL_CTL_ADD, dnsfds.second, &ev);
    epoll_ctl(epollfd, EPOLL_CTL_ADD, listenfd,      &ev);

    while (1) {
        // Wait for stuff to happen
        struct epoll_event t;
        epoll_wait(epollfd, &t, 1, 1000);
        
        // Receive packets!
        uint8_t inbuff[2048];
        struct sockaddr_storage addrstorage;
        socklen_t addrlen = sizeof(addrstorage);
        int received = recvfrom(listenfd, inbuff, sizeof(inbuff), MSG_DONTWAIT, (sockaddr*)&addrstorage, &addrlen);

        if (received > 0) {
            struct dns_packet pkt = parse_udp_packet(inbuff, received);

            // Just look at the first question for now
            if (pkt.questions.size() == 1 && pkt.questions[0].qclass == 1) {
                // Create response
                struct dns_response *dresp = new struct dns_response;

                dresp->pkt.header.tid = pkt.header.tid;
                dresp->pkt.header.nqueries = 1;
                dresp->pkt.header.nanswers = 0;
                dresp->pkt.header.nauth = 0;
                dresp->pkt.header.nother = 0;

                memcpy(&dresp->addrstorage, &addrstorage, addrlen);
                dresp->addrlen = addrlen;

                dresp->pkt.questions.push_back(pkt.questions[0]);

                dns->resolve(pkt.questions[0].name, (enum dns_record_type)pkt.questions[0].qtype,
                             resolved_cb, dresp, 0);
            }
        }

        // Process requests!
        dns->poll();
    }

    delete dns;

    return (EXIT_SUCCESS);
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x928, %rsp            # imm = 0x928
xorl %edi, %edi
movl $0xa, %esi
callq 0x4384
testq %rax, %rax
jne 0x37a8
movq 0xc84e(%rip), %rax      # 0xffd8
movq (%rax), %rcx
leaq 0x7870(%rip), %rdi      # 0xb004
movl $0x18, %esi
movl $0x1, %edx
callq 0x3460
jmp 0x3833
movq %rax, %rbx
leaq 0x90(%rsp), %r14
movq $0x0, 0x8(%r14)
movq $0x35000002, (%r14)     # imm = 0x35000002
movl $0x2, %edi
movl $0x2, %esi
xorl %edx, %edx
callq 0x30d0
movl %eax, 0xca87(%rip)      # 0x10260
leaq 0x34(%rsp), %rcx
movl $0x1, (%rcx)
movl %eax, %edi
movl $0x1, %esi
movl $0x2, %edx
movl $0x4, %r8d
callq 0x3410
movl 0xca5f(%rip), %edi      # 0x10260
movq %r14, %rsi
movl $0x10, %edx
callq 0x3090
testl %eax, %eax
jns 0x383d
callq 0x3050
movl (%rax), %esi
leaq 0x77fd(%rip), %rdi      # 0xb01d
xorl %eax, %eax
callq 0x3060
leaq 0x780b(%rip), %rdi      # 0xb039
callq 0x3240
movl $0x1, %edi
callq 0x3320
movl $0x1, %edi
callq 0x3430
movl %eax, %ebp
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x10(%rax)
movq %rax, %r14
shrq $0x20, %r14
leaq 0x78(%rsp), %r15
movl $0x1, (%r15)
movq $0x0, 0x4(%r15)
movl %ebp, %edi
movl $0x1, %esi
movl %eax, %edx
movq %r15, %rcx
callq 0x3370
movl %ebp, %edi
movl $0x1, %esi
movl %r14d, %edx
movq %r15, %rcx
callq 0x3370
movl 0xc9ca(%rip), %edx      # 0x10260
movl %ebp, %edi
movl $0x1, %esi
movq %r15, %rcx
callq 0x3370
leaq 0x48(%rsp), %r14
leaq 0x120(%rsp), %r15
movl %ebp, 0xc(%rsp)
movl %ebp, %edi
leaq 0x84(%rsp), %rsi
movl $0x1, %edx
movl $0x3e8, %ecx            # imm = 0x3E8
callq 0x3150
movl $0x80, 0x8(%rsp)
movl 0xc983(%rip), %edi      # 0x10260
movl $0x800, %edx            # imm = 0x800
movq %r15, %rsi
movl $0x40, %ecx
leaq 0xa0(%rsp), %r8
leaq 0x8(%rsp), %r9
callq 0x3210
testl %eax, %eax
jle 0x3a1b
leaq 0x38(%rsp), %rdi
movq %r15, %r13
movq %r15, %rsi
movl %eax, %edx
callq 0x9957
movq 0x48(%rsp), %r15
movq 0x50(%rsp), %rax
subq %r15, %rax
cmpq $0x28, %rax
jne 0x3a06
cmpw $0x1, 0x2(%r15)
jne 0x3a06
movl $0xc8, %edi
callq 0x32a0
movq %rax, %r12
leaq 0x10(%rax), %r14
xorps %xmm0, %xmm0
movups %xmm0, 0x30(%rax)
movups %xmm0, 0x20(%rax)
movups %xmm0, 0x10(%rax)
movzwl 0x38(%rsp), %eax
movw %ax, (%r12)
movq $0x1, 0x4(%r12)
movq %r12, %rdi
addq $0x40, %rdi
movl 0x8(%rsp), %ebp
leaq 0xa0(%rsp), %rsi
movq %rbp, %rdx
callq 0x3230
movl %ebp, 0xc0(%r12)
movq %r14, %rdi
leaq 0x48(%rsp), %r14
movq %r15, %rsi
callq 0x3b3e
movq 0x48(%rsp), %rax
leaq 0x20(%rsp), %rcx
movq %rcx, 0x10(%rsp)
movq 0x8(%rax), %rsi
movq 0x10(%rax), %rdx
addq %rsi, %rdx
leaq 0x10(%rsp), %rdi
callq 0x3c72
movq 0x48(%rsp), %rax
movzwl (%rax), %edx
movq (%rbx), %rax
movq %rbx, %rdi
leaq 0x10(%rsp), %rsi
leaq -0x341(%rip), %rcx      # 0x369c
movq %r12, %r8
xorl %r9d, %r9d
callq *0x18(%rax)
movq 0x10(%rsp), %rdi
leaq 0x20(%rsp), %rax
cmpq %rax, %rdi
movl 0xc(%rsp), %ebp
je 0x3a06
movq 0x20(%rsp), %rsi
incq %rsi
callq 0x32b0
leaq 0x60(%rsp), %rdi
callq 0x3b80
movq %r14, %rdi
callq 0x3bb0
movq %r13, %r15
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x28(%rax)
jmp 0x38b6
movq %rax, %rbx
movq 0x10(%rsp), %rdi
leaq 0x20(%rsp), %rax
cmpq %rax, %rdi
je 0x3a4d
movq 0x20(%rsp), %rsi
incq %rsi
callq 0x32b0
jmp 0x3a4d
movq %rax, %rbx
leaq 0x60(%rsp), %rdi
callq 0x3b80
movq %r14, %rdi
callq 0x3bb0
movq %rbx, %rdi
callq 0x3400
nop