// File: /workspace/github_cpp_makefile_star2_O2/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
pushq $0xa
popq %rsi
xorl %edi, %edi
callq 0x40e8
movq %rax, 0x8(%rsp)
testq %rax, %rax
jne 0x36d3
movq 0xc91c(%rip), %rax      # 0xffd8
movq (%rax), %rcx
leaq 0x693e(%rip), %rdi      # 0xa004
pushq $0x18
popq %rsi
pushq $0x1
popq %rdx
callq 0x3450
jmp 0x374c
leaq 0x90(%rsp), %r14
andq $0x0, 0x8(%r14)
movq $0x35000002, (%r14)     # imm = 0x35000002
pushq $0x2
popq %rbp
movl %ebp, %edi
movl %ebp, %esi
xorl %edx, %edx
callq 0x30c0
movl %eax, 0xcb6d(%rip)      # 0x10268
leaq 0x14(%rsp), %rcx
movl $0x1, (%rcx)
pushq $0x1
popq %rsi
pushq $0x4
popq %r8
movl %eax, %edi
movl %ebp, %edx
callq 0x3400
movl 0xcb4c(%rip), %edi      # 0x10268
pushq $0x10
popq %rdx
movq %r14, %rsi
callq 0x3080
testl %eax, %eax
jns 0x3754
callq 0x3040
movl (%rax), %esi
leaq 0x68e4(%rip), %rdi      # 0xa01d
xorl %eax, %eax
callq 0x3050
leaq 0x68f2(%rip), %rdi      # 0xa039
callq 0x3240
pushq $0x1
popq %rdi
callq 0x3300
pushq $0x1
popq %r14
movl %r14d, %edi
callq 0x3420
movl %eax, %r13d
movq 0x8(%rsp), %rdi
movq (%rdi), %rax
callq *0x10(%rax)
movq %rax, %r15
shrq $0x20, %r15
leaq 0x78(%rsp), %r12
movl $0x1, (%r12)
andq $0x0, 0x4(%r12)
movl %r13d, %edi
movl %r14d, %esi
movl %eax, %edx
movq %r12, %rcx
callq 0x3370
movl %r13d, %edi
movl %r14d, %esi
movl %r15d, %edx
movq %r12, %rcx
callq 0x3370
movl 0xcab9(%rip), %edx      # 0x10268
movl %r13d, %edi
movl %r14d, %esi
movq %r12, %rcx
callq 0x3370
leaq 0x120(%rsp), %r15
leaq 0x18(%rsp), %rbp
movl %r13d, 0x10(%rsp)
movl %r13d, %edi
leaq 0x84(%rsp), %rsi
movl %r14d, %edx
movl $0x3e8, %ecx            # imm = 0x3E8
callq 0x3150
movl $0x80, 0x4(%rsp)
movl 0xca73(%rip), %edi      # 0x10268
movl $0x800, %edx            # imm = 0x800
movq %r15, %rsi
pushq $0x40
popq %rcx
leaq 0xa0(%rsp), %r8
leaq 0x4(%rsp), %r9
callq 0x3210
testl %eax, %eax
jle 0x3908
movq %rbp, %rbx
movq %rbp, %rdi
movq %r15, %r12
movq %r15, %rsi
movl %eax, %edx
callq 0x8cf2
movq 0x28(%rsp), %rbp
movq 0x30(%rsp), %rax
subq %rbp, %rax
cmpq $0x28, %rax
jne 0x38fa
cmpw $0x1, 0x2(%rbp)
jne 0x38fa
movl $0xc8, %edi
callq 0x32a0
movq %rax, %r15
leaq 0x10(%rax), %r13
xorps %xmm0, %xmm0
movups %xmm0, 0x30(%rax)
movups %xmm0, 0x20(%rax)
movups %xmm0, 0x10(%rax)
movzwl 0x18(%rsp), %eax
movw %ax, (%r15)
movq $0x1, 0x4(%r15)
movq %r15, %rdi
addq $0x40, %rdi
movl 0x4(%rsp), %r14d
leaq 0xa0(%rsp), %rsi
movq %r14, %rdx
callq 0x3230
movl %r14d, 0xc0(%r15)
movq %r13, %rdi
movq %rbp, %rsi
callq 0x3a1a
movq 0x28(%rsp), %rsi
addq $0x8, %rsi
leaq 0x58(%rsp), %rdi
callq 0x3360
movq 0x28(%rsp), %rax
movzwl (%rax), %edx
movq 0x8(%rsp), %rdi
movq (%rdi), %rax
leaq 0x58(%rsp), %r14
movq %r14, %rsi
leaq -0x304(%rip), %rcx      # 0x35dc
movq %r15, %r8
xorl %r9d, %r9d
callq *0x18(%rax)
movq %r14, %rdi
callq 0x3140
pushq $0x1
popq %r14
movl 0x10(%rsp), %r13d
movq %rbx, %rbp
movq %rbx, %rdi
callq 0x3a46
movq %r12, %r15
movq 0x8(%rsp), %rdi
movq (%rdi), %rax
callq *0x28(%rax)
jmp 0x37cf
movq %rax, %rbx
leaq 0x58(%rsp), %rdi
callq 0x3140
jmp 0x392a
movq %rax, %rbx
leaq 0x18(%rsp), %rdi
callq 0x3a46
movq %rbx, %rdi
callq 0x33f0