Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- Sofia Gonçalves 2011158780
- Rodrigo Almeida 2013140729
- */
- // Includes
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <signal.h>
- #include <string.h>
- #include <sys/socket.h>
- #include <arpa/inet.h>
- #include <netinet/in.h>
- #include <unistd.h>
- #include <sys/ipc.h>
- #include <sys/shm.h>
- #include <sys/msg.h>
- #include <pthread.h>
- #include <semaphore.h>
- #include "includes.h"
- #include "structures.h"
- #include <sys/types.h>
- #include <sys/stat.h>
- #define MAX_LEN 300
- #define MAX_DOMAINS 100
- #define N_PROCESSES 2
- #define LOCAL_DNS_PATH "localdns.txt"
- /*--------------------------------*/
- // Global Variables
- pid_t processes[N_PROCESSES];
- ConfigMemory* config_memory;
- Host hosts[MAX_HOSTS];
- int shmid;
- pthread_t main_thread;
- List_high high;
- List normal;
- Threads threads; // Pool Threads
- pthread_mutex_t mutex; // Mutex of threads
- FILE * wr_stream,*rd_stream;
- int res;
- /*--------------------------------*/
- // Functions
- // Given Functions
- void convertName2RFC (unsigned char*,unsigned char*);
- unsigned char* convertRFC2Name (unsigned char*,unsigned char*,int*);
- void sendReply(unsigned short, unsigned char*, int, int, struct sockaddr_in);
- // Our Functions
- void readConfigFile();
- void read_localdns();
- int write_localdns(char endereco[]);
- void configProcess();
- void statsProcess();
- void requestProcess(int port);
- void print_list_high(List_high high);
- void print_list_normal(List normal);
- void go_through_high_list(List_high high, List_high *ant_high, List_high *useless_high);
- void go_through_normal_list(List normal, List *ant_normal, List *useless_normal);
- int empty_list_high(List_high high);
- int empty_list_normal(List normal);
- void remove_first_high(List_high high);
- void remove_first_normal(List normal);
- void destroy_high(List_high high);
- void destroy_normal(List normal);
- void init();
- void *mainThread(void *param);
- void terminate();
- void sigint(int sig);
- void sig_handler();
- void inicia_pipe();
- void envia_pipe(int action);
- int recebe_pipe();
- int main(int argc, char const *argv[]) {
- // Check arguments
- if(argc <= 1) {
- printf("Usage: dnsserver <port>\n");
- exit(1);
- }
- // Get server UDP port number
- int port = atoi(argv[1]);
- if(port <= 0) {
- printf("Usage: dnsserver <port>\n");
- exit(1);
- }
- //Init
- init();
- // Configuration Management Process
- if((processes[0]=fork())==0) {
- printf("\nInitializing Configuration Management Process (%d)...\n", getpid());
- configProcess();
- // Signal SIGUSR1
- if (signal(SIGUSR1, sig_handler) == SIG_ERR)
- printf("\ncan't catch SIGUSR1\n");
- if(signal(SIGINT,SIG_IGN)==SIG_ERR){
- perror("ERROR IGNORING SIGINT");
- exit(1);
- }
- // A long long wait so that we can easily issue a signal to this process
- while(1)
- sleep(1);
- return 0;
- exit(0);
- }
- // Wait For Configuration Management Process
- sleep(1);
- //Initialize pipe
- void inicia_pipe();
- // Statistics Process
- if((processes[1]=fork())==0) {
- printf("\nInitializing Statistics Process...\n");
- statsProcess();
- exit(0);
- }
- // Wait For Statistics Process
- sleep(1);
- // Create Main Thread
- if(pthread_create(&main_thread,NULL,mainThread,NULL)!=0){
- perror("\nCreating Main Thread...");
- terminate();
- }
- // Wait for Main Thread
- sleep(2);
- requestProcess(port);
- return 0;
- }
- // Configuration Management Process
- void configProcess() {
- int i;
- // Read config.txt
- readConfigFile();
- printf(" - Number of Threads: %d\n", config_memory->n_threads);
- printf(" - Domains (%d): ", config_memory->n_domains);
- for(i=0;i<config_memory->n_domains;i++) {
- if(i == config_memory->n_domains-1){
- printf("%s", config_memory->domains[i]);
- } else{
- printf("%s | ", config_memory->domains[i]);
- }
- }
- printf("\n");
- printf(" - Local Domain: %s\n", config_memory->local_domain);
- printf(" - Named Pipe: %s\n", config_memory->named_pipe);
- read_localdns();
- }
- void statsProcess(){
- int contador_pedidos = 0;
- int valor_pipe = 200;
- while(1){
- valor_pipe = recebe_pipe();
- if (valor_pipe == 1){
- contador_pedidos ++;
- printf("O contador de pedidos agora esta a %d\n",contador_pedidos);
- }
- }
- }
- void requestProcess(int port){
- unsigned char buf[65536], *reader;
- int sockfd, stop;
- struct DNS_HEADER *dns = NULL;
- struct sockaddr_in servaddr, dest;
- socklen_t len;
- // ****************************************
- // Create socket & bind
- // ****************************************
- // Create UDP socket
- sockfd = socket(AF_INET , SOCK_DGRAM , IPPROTO_UDP); //UDP packet for DNS queries
- if (sockfd < 0) {
- printf("ERROR opening socket.\n");
- exit(1);
- }
- // Prepare UDP to bind port
- bzero(&servaddr,sizeof(servaddr));
- servaddr.sin_family = AF_INET;
- servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
- servaddr.sin_port=htons(port);
- // Bind application to UDP port
- int res = bind(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
- if(res < 0) {
- printf("Error binding to port %d.\n", servaddr.sin_port);
- if(servaddr.sin_port <= 1024) {
- printf("To use ports below 1024 you may need additional permitions. Try to use a port higher than 1024.\n");
- } else {
- printf("Please make sure this UDP port is not being used.\n");
- }
- exit(1);
- }
- // ****************************************
- // Receive questions
- // ****************************************
- while(1) {
- List_high high_node;
- List_high ant_high;
- List_high useless_high;
- List normal_node;
- List ant_normal;
- List useless_normal;
- high_node = (List_high)malloc(sizeof(list_node_high));
- ant_high = (List_high)malloc(sizeof(list_node_high));
- useless_high = (List_high)malloc(sizeof(list_node_high));
- normal_node = (List)malloc(sizeof(list_node));
- ant_normal = (List)malloc(sizeof(list_node));
- useless_normal = (List)malloc(sizeof(list_node));
- // Receive questions
- len = sizeof(dest);
- printf("\n\n-- Wating for DNS message --\n\n");
- if(recvfrom (sockfd,(char*)buf , 65536 , 0 , (struct sockaddr*)&dest , &len) < 0) {
- printf("Error while waiting for DNS message. Exiting...\n");
- exit(1);
- }
- printf("DNS message received\n");
- // Process received message
- dns = (struct DNS_HEADER*) buf;
- //qname =(unsigned char*)&buf[sizeof(struct DNS_HEADER)];
- reader = &buf[sizeof(struct DNS_HEADER)];
- printf("\nThe query %d contains: ", ntohs(dns->id));
- printf("\n %d Questions.",ntohs(dns->q_count));
- printf("\n %d Answers.",ntohs(dns->ans_count));
- printf("\n %d Authoritative Servers.",ntohs(dns->auth_count));
- printf("\n %d Additional records.\n\n",ntohs(dns->add_count));
- // We only need to process the questions
- // We only process DNS messages with one question
- // Get the query fields according to the RFC specification
- struct QUERY query;
- if(ntohs(dns->q_count) == 1) {
- // Get NAME
- query.name = convertRFC2Name(reader,buf,&stop);
- reader = reader + stop;
- // Get QUESTION structure
- query.ques = (struct QUESTION*)(reader);
- reader = reader + sizeof(struct QUESTION);
- // Check question type. We only need to process A records.
- if(ntohs(query.ques->qtype) == 1) {
- printf("A record request.\n\n");
- } else {
- printf("NOT A record request!! Ignoring DNS message!\n");
- continue;
- }
- } else {
- printf("\n\nDNS message must contain one question!! Ignoring DNS message!\n\n");
- continue;
- }
- // Received DNS message fulfills all requirements.
- // ****************************************
- // Print received DNS message QUERY
- // ****************************************
- printf(">> QUERY: %s\n", query.name);
- printf(">> Type (A): %d\n", ntohs(query.ques->qtype));
- printf(">> Class (IN): %d\n\n", ntohs(query.ques->qclass));
- int valor_pipe = 1;
- // Check Domain
- if(strstr((char*)query.name, config_memory->local_domain) != NULL){
- printf(">>> Its a local domain!\n");
- printf(">>> Goes to High Priority Queue!\n");
- if(high_node != NULL){
- high_node->info = dns;
- high_node->dest = dest;
- high_node->sockfd = sockfd;
- high_node->name = query.name;
- go_through_high_list(high, &ant_high, &useless_high);
- high_node->next = ant_high->next;
- ant_high->next = high_node;
- envia_pipe(valor_pipe); //envia o valor 1 ao pipe para ele saber que ha mais um request
- }
- } else{
- printf(">>> Its an external domain!\n");
- printf(">>> Goes to Normal Priority Queue!\n");
- if(normal_node != NULL){
- normal_node->info = dns;
- normal_node->dest = dest;
- normal_node->sockfd = sockfd;
- normal_node->name = query.name;
- go_through_normal_list(normal, &ant_normal, &useless_normal);
- normal_node->next = ant_normal->next;
- ant_normal->next = normal_node;
- envia_pipe(valor_pipe); //envia o valor 1 ao pipe para ele saber que ha mais um request
- }
- }
- }
- }
- int write_localdns(char endereco[]){
- FILE *fp;
- fp = fopen(LOCAL_DNS_PATH,"a");
- if( fp == NULL )
- {
- printf("ERROR:I can't open the file \n");
- exit(1);
- }
- fprintf(fp, "%s\n", endereco);
- fclose(fp); //closing the file
- return 1;
- }
- // Worker Thread (Thread in Pool)
- void *worker_thread(void * ptr_thread) {
- FILE* in;
- extern FILE *popen();
- char buff[512];
- int i;
- Thread* thread = (Thread*) ptr_thread;
- while(1) {
- char command[MAX_LEN];
- read_localdns();
- pthread_mutex_lock(&(thread->mutex));
- while(thread->flag == 0){
- pthread_cond_wait(&(thread->cond),&(thread->mutex));
- }
- thread->flag = 1;
- pthread_mutex_unlock(&(thread->mutex));
- // Deals with Request
- if(strstr((char*)thread->name, config_memory->local_domain) != NULL){
- for(i=0; i<hosts[0].size_array; i++){
- if(strcmp(hosts[i].host_name, (char*)thread->name) == 0){
- sendReply(thread->request->id, thread->name, inet_addr(hosts[i].ip), thread->sockfd, thread->origin);
- break;
- }
- }
- } else{
- for(i=0; i<config_memory->n_domains; i++){
- if(strstr((char*)thread->name, config_memory->domains[i]) != NULL){
- strcpy(command, "dig +short ");
- strcat(command, (char*)thread->name);
- if(!(in = popen(command, "r"))){
- exit(1);
- }
- while(fgets(buff, sizeof(buff), in)!=NULL){
- sendReply(thread->request->id, thread->name, inet_addr(buff), thread->sockfd, thread->origin);
- break;
- }
- if(fgets(buff, sizeof(buff), in) == NULL){
- sendReply(thread->request->id, thread->name, inet_addr("0.0.0.0"), thread->sockfd, thread->origin);
- }
- pclose(in);
- break;
- } else{
- if(i == config_memory->n_domains -1){
- printf("That is not a valid external domain!\n");
- break;
- }
- }
- }
- }
- sleep(3);
- //Set thread as available
- threads.list[thread->id].flag = 0;
- printf("Dealt by Thread (%d)\n",thread->id);
- }
- return NULL;
- }
- void *mainThread(void *param){
- int i = 0;
- printf("\nInitializing Threads...\n");
- // Create Pool Threads
- threads.list = (Thread*) malloc ((config_memory->n_threads)*sizeof(Thread));
- for(i=0;i<config_memory->n_threads;i++) {
- if(pthread_create(&threads.list[i].thread,NULL,worker_thread,&threads.list[i])!=0){
- perror("thread pool\n");
- terminate();
- }
- threads.list[i].id = i;
- threads.list[i].flag = 0;
- threads.list[i].request = NULL;
- threads.list[i].cond = (pthread_cond_t)PTHREAD_COND_INITIALIZER;
- threads.list[i].mutex = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
- }
- sleep(1);
- printf(" - Main Thread...\n");
- printf(" - Pool Threads...\n");
- while(1){
- //Primeiro temos a prioridade alta e depois vem a prioridade normal
- // Check Lists - verifica se as listas estao ou nao vazias
- if(empty_list_high(high) != 1){ //The list is not empty if the returned value is != 0 // Verifify if there are request with high Priority
- // Choose a thread free to solve the problem
- for(i=0;i<config_memory->n_threads;i++){
- // Thread Available
- if(threads.list[i].flag == 0) {
- // Sinalize Request In Thread --> Dar o primeiro no 'a thread e elimina-lo da lista
- threads.list[i].request = high->next->info;
- threads.list[i].sockfd = high->next->sockfd;
- threads.list[i].origin = high->next->dest;
- threads.list[i].name = high->next->name;
- remove_first_high(high);
- // Set Thread as Unavailable
- threads.list[i].flag = 1;
- // Call Worker Thread
- if(pthread_cond_signal(&threads.list[i].cond)!=0){
- perror("pthread cond signal");
- terminate();
- }
- break;
- }
- }
- } else if(empty_list_normal(normal) != 1){ // If not, take a request from normal priority
- if((config_memory->flag == 0) && (empty_list_normal(normal) != 1)){ // Check config_memory_flag --> Só resolve requests de high priority (SIGUSR1) //The list is not empty if the returned value is != 0 // Verifify if there are request with normal Priority
- // Choose a thread free to solve the problem
- for(i=0;i<config_memory->n_threads;i++) {
- // Thread Available
- if(threads.list[i].flag == 0) {
- pthread_mutex_unlock(&(threads.list[i].mutex));
- // Sinalize Request In Thread --> Dar o primeiro no 'a thread e elimina-lo da lista
- threads.list[i].request = normal->next->info;
- threads.list[i].sockfd = normal->next->sockfd;
- threads.list[i].origin = normal->next->dest;
- threads.list[i].name = normal->next->name;
- remove_first_normal(normal);
- threads.list[i].flag = 1; // Set Thread as Unavailable
- // Call Worker Thread
- if(pthread_cond_signal(&threads.list[i].cond)!=0){
- perror("pthread cond signal");
- terminate();
- }
- pthread_mutex_unlock(&(threads.list[i].mutex));
- break;
- }
- }
- }
- }
- }
- }
- void init() {
- printf("--- Initializing ---\n\n");
- printf("Initializing Resources...\n");
- // Catch Signals
- printf(" - Catch Signals...\n");
- if(signal(SIGINT, sigint)==SIG_ERR){
- perror("sigint");
- exit(0);
- }
- // Initialize Shared Memory
- printf(" - Shared Memory...\n");
- // - Connect to (and possibly create) the segment
- if ((shmid = shmget(IPC_PRIVATE, sizeof(ConfigMemory), IPC_CREAT|0700)) == -1) {
- perror("shmget");
- terminate();
- }
- // - Attach to the segment to get a pointer to it
- config_memory = (ConfigMemory*) shmat(shmid, NULL, 0);
- if (config_memory == (ConfigMemory*)(-1)) {
- perror("shmat");
- terminate();
- }
- // Initialize High Priority Queue
- printf(" - High Priority Queue...\n");
- high = (List_high) malloc(sizeof(list_node_high));
- high->info = malloc(sizeof(struct DNS_HEADER*));
- if(high != NULL){
- high->info->id = 0;
- high->next = NULL;
- }
- // Initialize Normal Priority Queue
- printf(" - Normal Priority Queue...\n");
- normal = (List) malloc(sizeof(list_node));
- normal->info = malloc(sizeof(struct DNS_HEADER*));
- if(normal != NULL){
- normal->info->id = 0;
- normal->next = NULL;
- }
- }
- void inicia_pipe(){
- remove(config_memory->named_pipe);
- if (access(config_memory->named_pipe, F_OK) == -1) { //verifica se o FIFO já existe
- res = mkfifo(config_memory->named_pipe,S_IRWXU);
- if (res != 0) {
- fprintf(stderr, "Não consegui abrir o FIFO %s\n", config_memory->named_pipe);
- exit(0);
- }
- else{
- //printf("INICIEI O PIPE\n");
- }
- }
- }
- void envia_pipe(int action){
- wr_stream = fopen(config_memory->named_pipe,"w");
- fwrite(&action,sizeof(int),1,wr_stream);
- fclose(wr_stream);
- }
- int recebe_pipe(){
- int action = -1;
- rd_stream = fopen(config_memory->named_pipe,"r"); /* open fifo in read-only mode */
- fread(&action,sizeof(int),1,rd_stream);
- printf("ACTION : %d \n", action);
- fclose(rd_stream); /* close the fifo */
- return action;
- }
- // Terminate Server
- void terminate() {
- int i;
- printf("\n--- Terminating ---\n\n");
- // Kill Child Processes
- printf("Killing Child Processes...\n");
- for(i=0;i<N_PROCESSES;i++) {
- kill(processes[i], SIGTERM);
- printf(" - Child Process %i Killed!\n", i);
- }
- printf("\n");
- // Destroy Threads
- pthread_cancel(main_thread);
- printf("Destroying Threads...\n");
- for(i=0;i<config_memory->n_threads;i++){
- pthread_mutex_destroy(&(threads.list[i].mutex));
- pthread_cancel(threads.list[i].thread);
- }
- printf(" - DONE!\n");
- // Destroy Shared Memory
- printf("Destroying Shared Memory...\n");
- shmdt(config_memory);
- shmctl(shmid, IPC_RMID, NULL);
- printf(" - DONE!\n");
- // Destroy Lists
- printf("Destroying Priority Lists...\n");
- destroy_normal(normal);
- destroy_high(high);
- printf(" - DONE!\n");
- exit(0);
- }
- // Functions from dnsserver.c
- /**
- sendReply: this method sends a DNS query reply to the client
- * id: DNS message id (required in the reply)
- * query: the requested query name (required in the reply)
- * ip_addr: the DNS lookup reply (the actual value to reply to the request)
- * sockfd: the socket to use for the reply
- * dest: the UDP package structure with the information of the DNS query requestor (includes it's IP and port to send the reply)
- **/
- void sendReply(unsigned short id, unsigned char* query, int ip_addr, int sockfd, struct sockaddr_in dest) {
- unsigned char bufReply[65536], *rname;
- char *rip;
- struct R_DATA *rinfo = NULL;
- //Set the DNS structure to reply (according to the RFC)
- struct DNS_HEADER *rdns = NULL;
- rdns = (struct DNS_HEADER *)&bufReply;
- rdns->id = id;
- rdns->qr = 1;
- rdns->opcode = 0;
- rdns->aa = 1;
- rdns->tc = 0;
- rdns->rd = 0;
- rdns->ra = 0;
- rdns->z = 0;
- rdns->ad = 0;
- rdns->cd = 0;
- rdns->rcode = 0;
- rdns->q_count = 0;
- rdns->ans_count = htons(1);
- rdns->auth_count = 0;
- rdns->add_count = 0;
- // Add the QUERY name (the same as the query received)
- rname = (unsigned char*)&bufReply[sizeof(struct DNS_HEADER)];
- convertName2RFC(rname , query);
- // Add the reply structure (according to the RFC)
- rinfo = (struct R_DATA*)&bufReply[sizeof(struct DNS_HEADER) + (strlen((const char*)rname)+1)];
- rinfo->type = htons(1);
- rinfo->_class = htons(1);
- rinfo->ttl = htonl(3600);
- rinfo->data_len = htons(sizeof(ip_addr)); // Size of the reply IP address
- // Add the reply IP address for the query name
- rip = (char *)&bufReply[sizeof(struct DNS_HEADER) + (strlen((const char*)rname)+1) + sizeof(struct R_DATA)];
- memcpy(rip, (struct in_addr *) &ip_addr, sizeof(ip_addr));
- // Send DNS reply
- printf("\nSending Answer... ");
- if( sendto(sockfd, (char*)bufReply, sizeof(struct DNS_HEADER) + (strlen((const char*)rname) + 1) + sizeof(struct R_DATA) + sizeof(ip_addr),0,(struct sockaddr*)&dest,sizeof(dest)) < 0) {
- printf("FAILED!!\n");
- } else {
- printf("SENT!!!\n");
- }
- }
- /**
- convertRFC2Name: converts DNS RFC name to name
- **/
- u_char* convertRFC2Name(unsigned char* reader,unsigned char* buffer,int* count) {
- unsigned char *name;
- unsigned int p=0,jumped=0,offset;
- int i , j;
- *count = 1;
- name = (unsigned char*)malloc(256);
- name[0]='\0';
- while(*reader!=0) {
- if(*reader>=192) {
- offset = (*reader)*256 + *(reader+1) - 49152;
- reader = buffer + offset - 1;
- jumped = 1;
- } else {
- name[p++]=*reader;
- }
- reader = reader+1;
- if(jumped==0) {
- *count = *count + 1;
- }
- }
- name[p]='\0';
- if(jumped==1) {
- *count = *count + 1;
- }
- for(i=0;i<(int)strlen((const char*)name);i++) {
- p=name[i];
- for(j=0;j<(int)p;j++) {
- name[i]=name[i+1];
- i=i+1;
- }
- name[i]='.';
- }
- name[i-1]='\0';
- return name;
- }
- /**
- convertName2RFC: converts name to DNS RFC name
- **/
- void convertName2RFC(unsigned char* dns,unsigned char* host) {
- int lock = 0 , i;
- strcat((char*)host,".");
- for(i = 0 ; i < strlen((char*)host) ; i++) {
- if(host[i]=='.') {
- *dns++ = i-lock;
- for(;lock<i;lock++) {
- *dns++=host[lock];
- }
- lock++;
- }
- }
- *dns++='\0';
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement