// File: 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
movq %rsp, %rbp
subq $0x980, %rsp            # imm = 0x980
movl $0x0, -0x4(%rbp)
movl %edi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movl $0x35, -0x14(%rbp)
xorl %eax, %eax
movl %eax, %edi
movl $0xa, %esi
callq 0x5f40
movq %rax, -0x20(%rbp)
cmpq $0x0, %rax
jne 0x395a
movq 0x22691(%rip), %rax     # 0x25fd0
movq (%rax), %rdi
leaq 0x156bb(%rip), %rsi     # 0x19004
movb $0x0, %al
callq 0x34b0
movl $0x1, %edi
callq 0x3410
leaq -0x30(%rbp), %rdi
xorl %esi, %esi
movl $0x10, %edx
callq 0x31b0
movw $0x2, -0x30(%rbp)
xorl %edi, %edi
callq 0x3280
movl %eax, -0x2c(%rbp)
movl -0x14(%rbp), %eax
movzwl %ax, %edi
callq 0x3070
movw %ax, -0x2e(%rbp)
movl $0x2, %esi
xorl %edx, %edx
movl %esi, %edi
callq 0x30f0
movl %eax, 0x22983(%rip)     # 0x26320
movl $0x1, -0x34(%rbp)
movl 0x22976(%rip), %edi     # 0x26320
movl $0x1, %esi
movl $0x2, %edx
leaq -0x34(%rbp), %rcx
movl $0x4, %r8d
callq 0x3550
movl 0x22957(%rip), %edi     # 0x26320
leaq -0x30(%rbp), %rsi
movl $0x10, %edx
callq 0x30a0
cmpl $0x0, %eax
jge 0x3a07
callq 0x3050
movl (%rax), %esi
leaq 0x15633(%rip), %rdi     # 0x1901d
movb $0x0, %al
callq 0x3060
leaq 0x15641(%rip), %rdi     # 0x19039
callq 0x32d0
movl $0x1, %edi
callq 0x3410
movl $0x1, %edi
callq 0x3580
movl %eax, -0x38(%rbp)
movq -0x20(%rbp), %rdi
movq (%rdi), %rax
callq *0x10(%rax)
movq %rax, -0x40(%rbp)
movl $0x1, -0x4c(%rbp)
movq $0x0, -0x48(%rbp)
movl -0x38(%rbp), %edi
movl -0x40(%rbp), %edx
movl $0x1, %esi
leaq -0x4c(%rbp), %rcx
callq 0x3490
movl -0x38(%rbp), %edi
movl -0x3c(%rbp), %edx
movl $0x1, %esi
leaq -0x4c(%rbp), %rcx
callq 0x3490
movl -0x38(%rbp), %edi
movl 0x228be(%rip), %edx     # 0x26320
movl $0x1, %esi
leaq -0x4c(%rbp), %rcx
callq 0x3490
movl -0x38(%rbp), %edi
leaq -0x58(%rbp), %rsi
movl $0x1, %edx
movl $0x3e8, %ecx            # imm = 0x3E8
callq 0x3190
movl $0x80, -0x8e4(%rbp)
movl 0x2288a(%rip), %edi     # 0x26320
leaq -0x860(%rbp), %rsi
movl $0x800, %edx            # imm = 0x800
movl $0x40, %ecx
leaq -0x8e0(%rbp), %r8
leaq -0x8e4(%rbp), %r9
callq 0x3290
movl %eax, -0x8e8(%rbp)
cmpl $0x0, -0x8e8(%rbp)
jle 0x3ccd
leaq -0x860(%rbp), %rsi
movl -0x8e8(%rbp), %edx
leaq -0x928(%rbp), %rdi
callq 0x17660
leaq -0x928(%rbp), %rdi
addq $0x10, %rdi
callq 0x4040
cmpq $0x1, %rax
jne 0x3cb1
leaq -0x928(%rbp), %rdi
addq $0x10, %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x4070
movzwl 0x2(%rax), %eax
cmpl $0x1, %eax
jne 0x3cb1
movl $0xc8, %edi
callq 0x3350
movq %rax, -0x968(%rbp)
jmp 0x3b34
movq -0x968(%rbp), %rdi
callq 0x4090
movq -0x968(%rbp), %rax
movq %rax, -0x930(%rbp)
movw -0x928(%rbp), %cx
movq -0x930(%rbp), %rax
movw %cx, (%rax)
movq -0x930(%rbp), %rax
movw $0x1, 0x4(%rax)
movq -0x930(%rbp), %rax
movw $0x0, 0x6(%rax)
movq -0x930(%rbp), %rax
movw $0x0, 0x8(%rax)
movq -0x930(%rbp), %rax
movw $0x0, 0xa(%rax)
movq -0x930(%rbp), %rdi
addq $0x40, %rdi
movl -0x8e4(%rbp), %eax
movl %eax, %edx
leaq -0x8e0(%rbp), %rsi
callq 0x32c0
movl -0x8e4(%rbp), %ecx
movq -0x930(%rbp), %rax
movl %ecx, 0xc0(%rax)
movq -0x930(%rbp), %rax
addq $0x10, %rax
movq %rax, -0x970(%rbp)
leaq -0x918(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x4070
movq -0x970(%rbp), %rdi
movq %rax, %rsi
callq 0x40b0
jmp 0x3bf8
movq -0x20(%rbp), %rax
movq %rax, -0x978(%rbp)
leaq -0x918(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x4070
movq %rax, %rsi
addq $0x8, %rsi
leaq -0x960(%rbp), %rdi
callq 0x3160
jmp 0x3c28
leaq -0x918(%rbp), %rdi
xorl %eax, %eax
movl %eax, -0x97c(%rbp)
movl %eax, %esi
callq 0x4070
movq -0x978(%rbp), %rdi
movl -0x97c(%rbp), %r9d
movzwl (%rax), %edx
movq -0x930(%rbp), %r8
movq (%rdi), %rax
movq 0x18(%rax), %rax
leaq -0x4e4(%rip), %rcx      # 0x3780
leaq -0x960(%rbp), %rsi
callq *%rax
jmp 0x3c6f
leaq -0x960(%rbp), %rdi
callq 0x3200
jmp 0x3cb1
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x938(%rbp)
movl %eax, -0x93c(%rbp)
jmp 0x3cbf
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x938(%rbp)
movl %eax, -0x93c(%rbp)
leaq -0x960(%rbp), %rdi
callq 0x3200
jmp 0x3cbf
leaq -0x928(%rbp), %rdi
callq 0x4120
jmp 0x3ccd
leaq -0x928(%rbp), %rdi
callq 0x4120
jmp 0x3cdc
movq -0x20(%rbp), %rdi
movq (%rdi), %rax
callq *0x28(%rax)
jmp 0x3a70
movq -0x938(%rbp), %rdi
callq 0x3530
nopl (%rax,%rax)