⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dns.c

📁 浏览器的源代码,可移植到嵌入式设备.
💻 C
字号:
/* * File: dns.c * * Copyright (C) 1999, 2000, 2001 Jorge Arellano Cid <jcid@dillo.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. *//* * Non blocking pthread-handled Dns scheme */#include <pthread.h>#include <glib.h>#include <netdb.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <errno.h>#include <unistd.h>#include <stdlib.h>#include <stdio.h>#include <signal.h>#include <string.h>#include "msg.h"#include "dns.h"#include "list.h"#define DEBUG_LEVEL 5#include "debug.h"/* * Note: comment the following line for debugging or gprof profiling. */#define G_DNS_THREADED/* * Uncomment the following line for libc5 optimization *//* #define LIBC5 *//* Maximum dns resolving threads */#ifdef G_DNS_THREADED#  define G_DNS_MAX_SERVERS 4#else#  define G_DNS_MAX_SERVERS 1#endiftypedef struct {   gint channel;         /* Index of this channel [0 based] */   gboolean in_use;      /* boolean to tell if server is doing a lookup */   gboolean ip_ready;    /* boolean: is IP lookup done? */   GSList *addr_list;    /* IP address */   char *hostname;       /* Adress to resolve */   guint timeout_id;     /* gtk timeout function ID */#ifdef G_DNS_THREADED   pthread_t th1;        /* Thread id */#endif} DnsServer;typedef struct {   char *hostname;          /* host name for cache */   GSList *addr_list;       /* address of host */} GDnsCache;typedef struct {   gint channel;    /* -2 if waiting, otherwise index to dns_server[] */   char *hostname;  /* The one we're resolving */   ChainLink *Info; /* CCC info */} GDnsQueue;/* * Forward declarations */static gboolean Dns_timeout_client(gpointer data);/* * Local Data */static DnsServer dns_server[G_DNS_MAX_SERVERS];static gint num_servers;static GDnsCache *dns_cache;static gint dns_cache_size, dns_cache_size_max;static GDnsQueue *dns_queue;static gint dns_queue_size, dns_queue_size_max;static gboolean ipv6_enabled;/* ---------------------------------------------------------------------- *  Dns queue functions */static void Dns_queue_add(ChainLink *Info, gint channel, const char *hostname){   a_List_add(dns_queue, dns_queue_size, dns_queue_size_max);   dns_queue[dns_queue_size].Info = Info;   dns_queue[dns_queue_size].channel = channel;   dns_queue[dns_queue_size].hostname = g_strdup(hostname);   dns_queue_size++;}/* * Find hostname index in dns_queue * (if found, returns queue index; -1 if not) */static gint Dns_queue_find(const char *hostname){   gint i;   for (i = 0; i < dns_queue_size; i++)      if (!strcmp(hostname, dns_queue[i].hostname))         return i;   return -1;}/* * Given an index, remove an entry from the dns_queue */static void Dns_queue_remove(int index){   gint i;   DEBUG_MSG(2, "Dns_queue_remove: deleting client [%d] [queue_size=%d]\n",             index, dns_queue_size);   if (index < dns_queue_size) {      g_free(dns_queue[index].hostname);      --dns_queue_size;         /* you'll find out why ;-) */      for (i = index; i < dns_queue_size; i++)         dns_queue[i] = dns_queue[i + 1];   }}/* * Debug function *void Dns_queue_print(){   gint i;   MSG("Queue: [");   for (i = 0; i < dns_queue_size; i++)      MSG("%d:%s ", dns_queue[i].channel, dns_queue[i].hostname);   MSG("]\n");} *//* *  Given a CCC Info, remove its client */static void Dns_abort_by_ccc(ChainLink *Info){   gint i;   for (i = 0; i < dns_queue_size; i++)      if (dns_queue[i].Info == Info) {         Dns_queue_remove(i);         break;      }}/* *  Add an IP/hostname pair to Dns-cache */static void Dns_cache_add(char *hostname, GSList *addr_list){   a_List_add(dns_cache, dns_cache_size, dns_cache_size_max);   dns_cache[dns_cache_size].hostname = g_strdup(hostname);   dns_cache[dns_cache_size].addr_list = addr_list;   ++dns_cache_size;   DEBUG_MSG(1, "Cache objects: %d\n", dns_cache_size);}/* *  Initializer function */void a_Dns_init(void){   gint i;   DEBUG_MSG(5, "dillo_dns_init: Here we go!\n");   dns_queue_size = 0;   dns_queue_size_max = 16;   dns_queue = g_new(GDnsQueue, dns_queue_size_max);   dns_cache_size = 0;   dns_cache_size_max = 16;   dns_cache = g_new(GDnsCache, dns_cache_size_max);   num_servers = G_DNS_MAX_SERVERS;   /* Initialize servers data */   for (i = 0; i < num_servers; ++i) {      dns_server[i].channel = i;      dns_server[i].in_use = FALSE;      dns_server[i].ip_ready = FALSE;      dns_server[i].addr_list = NULL;      dns_server[i].hostname = NULL;      dns_server[i].timeout_id = 0;#ifdef G_DNS_THREADED      dns_server[i].th1 = (pthread_t) -1;#endif   }   /* IPv6 test */   ipv6_enabled = FALSE;#ifdef ENABLE_IPV6   {      /* If the IPv6 address family is not available there is no point         wasting time trying to connect to v6 addresses. */      int fd = socket(AF_INET6, SOCK_STREAM, 0);      if (fd >= 0) {         close(fd);         ipv6_enabled = TRUE;      }   }#endif}/* * Allocate a host structure and add it to the list */static GSList *Dns_note_hosts(GSList *list, int af, struct hostent *host){   int i;   if (host->h_length > DILLO_ADDR_MAX)      return list;   for (i = 0; host->h_addr_list[i]; i++) {      DilloHost *dh = g_new0(DilloHost, 1);      dh->af = af;      dh->alen = host->h_length;      memcpy(&dh->data[0], host->h_addr_list[i], host->h_length);      list = g_slist_append(list, dh);   }   return list;}/* *  Server function (runs on its own thread) */static void *Dns_server(void *data){   struct hostent *host;   gint channel = GPOINTER_TO_INT(data);#ifdef LIBC5   gint h_err;   char buff[1024];   struct hostent sh;#endif   GSList *hosts = NULL;#ifdef G_DNS_THREADED   /* Set this thread to detached state */   pthread_detach(dns_server[channel].th1);#endif   DEBUG_MSG(3, "Dns_server: starting...\n ch: %d host: %s\n",             channel, dns_server[channel].hostname);#ifdef ENABLE_IPV6   if (ipv6_enabled) {      host = gethostbyname2(dns_server[channel].hostname, AF_INET6);      if (host)         hosts = Dns_note_hosts(hosts, AF_INET6, host);   }#endif#ifdef LIBC5   host = gethostbyname_r(dns_server[channel].hostname, &sh, buff,                          sizeof(buff), &h_err);#else   host = gethostbyname(dns_server[channel].hostname);#endif   if (host)      hosts = Dns_note_hosts(hosts, AF_INET, host);   /* write hostname to client */   DEBUG_MSG(5, "Dns_server [%d]: %s is %p\n", channel,             dns_server[channel].hostname, hosts);   dns_server[channel].addr_list = hosts;   dns_server[channel].ip_ready = TRUE;   return NULL;                 /* (avoids a compiler warning) */}#ifndef G_DNS_THREADED/* *  Blocking server-function (it doesn't use threads) */static void Dns_blocking_server(void){   gint channel = 0;   struct hostent *host = NULL;   GSList *hosts = NULL;   DEBUG_MSG(3, "Dns_blocking_server: starting...\n");   DEBUG_MSG(3, "Dns_blocking_server: dns_server[%d].hostname = %s\n",             channel, dns_server[channel].hostname);#ifdef ENABLE_IPV6   if (ipv6_enabled) {      host = gethostbyname2(dns_server[channel].hostname, AF_INET6);      if (host)         hosts = Dns_note_hosts(hosts, AF_INET6, host);   }#endif   if (!host) {      host = gethostbyname(dns_server[channel].hostname);      if (host == NULL) {         DEBUG_MSG(3, "--> Dns_blocking_server: gethostbyname NULL return\n");      } else {         DEBUG_MSG(3, "--> Dns_blocking_server - good return\n");         hosts = Dns_note_hosts(hosts, AF_INET, host);      }   }   /* write IP to server data channel */   DEBUG_MSG(3, "Dns_blocking_server: IP of %s is %p\n",             dns_server[channel].hostname, hosts);   dns_server[channel].addr_list = hosts;   dns_server[channel].ip_ready = TRUE;   DEBUG_MSG(3, "Dns_blocking_server: leaving...\n");}#endif/* *  Request function (spawn a server and let it handle the request) */static void Dns_server_req(gint channel, const char *hostname){   dns_server[channel].in_use = TRUE;   dns_server[channel].ip_ready = FALSE;   g_free(dns_server[channel].hostname);   dns_server[channel].hostname = g_strdup(hostname);   /* Let's set a timeout client to poll the server channel (5 times/sec) */   dns_server[channel].timeout_id =      gtk_timeout_add(200, (GtkFunction)Dns_timeout_client,                      GINT_TO_POINTER(dns_server[channel].channel));#ifdef G_DNS_THREADED   /* Spawn thread */   pthread_create(&dns_server[channel].th1, NULL, Dns_server,                  GINT_TO_POINTER(dns_server[channel].channel));#else   Dns_blocking_server();#endif}/* * Return the IP for the given hostname. * Side effect: a thread can be spawned later. */static void Dns_lookup(ChainLink *Info, const char *hostname){   gint i, channel;   g_return_if_fail (hostname != NULL);   /* check for cache hit. */   for (i = 0; i < dns_cache_size; i++)      if (!strcmp(hostname, dns_cache[i].hostname))         break;   /* if it hits already resolved, call the Callback inmediately. */   if (i < dns_cache_size) {      a_Dns_ccc(OpSend, 1, FWD, Info, dns_cache[i].addr_list, NULL);      a_Dns_ccc(OpEnd, 1, FWD, Info, NULL, NULL);      return;   }   if ((i = Dns_queue_find(hostname)) != -1) {      /* hit in queue, but answer hasn't come back yet. */      Dns_queue_add(Info, dns_queue[i].channel, hostname);   } else {      /* Never requested before -- we must solve it! */      /* Find a channel we can send the request to */      for (channel = 0; channel < num_servers; channel++)         if (!dns_server[channel].in_use)            break;      if (channel < num_servers) {         /* Found a free channel! */         Dns_queue_add(Info, channel, hostname);         Dns_server_req(channel, hostname);      } else {         /* We'll have to wait for a thread to finish... */         Dns_queue_add(Info, -2, hostname);      }   }}/* * Give answer to all queued callbacks on this channel */static void Dns_serve_channel(gint channel){   gint i;   ChainLink *Info;   DnsServer *srv = &dns_server[channel];   for (i = 0; i < dns_queue_size; i++) {      if (dns_queue[i].channel == channel) {         Info = dns_queue[i].Info;         if ( srv->addr_list == NULL ) {            a_Dns_ccc(OpAbort, 1, FWD, Info, NULL, NULL);         } else {            a_Dns_ccc(OpSend, 1, FWD, Info, srv->addr_list, NULL);            a_Dns_ccc(OpEnd, 1, FWD, Info, NULL, NULL);         }         Dns_queue_remove(i);         --i;      }   }   /* set current channel free */   srv->in_use = FALSE;}/* * Assign free channels to waiting clients (-2) */static void Dns_assign_channels(void){   gint ch, i, j;   for (ch = 0; ch < num_servers; ++ch) {      if (dns_server[ch].in_use == FALSE) {         /* Find the next query in the queue (we're a FIFO) */         for (i = 0; i < dns_queue_size; i++)            if (dns_queue[i].channel == -2)               break;         if (i < dns_queue_size) {            /* assign this channel to every queued request             * with the same hostname*/            for (j = i; j < dns_queue_size; j++)               if (dns_queue[j].channel == -2 &&                   !strcmp(dns_queue[j].hostname, dns_queue[i].hostname))                  dns_queue[j].channel = ch;            Dns_server_req(ch, dns_queue[i].hostname);         } else            return;      }   }}/* * This is a Gtk+ timeout function that * reads the DNS results and resumes the stopped jobs. */static gboolean Dns_timeout_client(gpointer data){   gint channel = GPOINTER_TO_INT(data);   DnsServer *srv = &dns_server[channel];   if ( srv->ip_ready ){      if (srv->addr_list != NULL) {         /* DNS succeeded, let's cache it */         Dns_cache_add(srv->hostname, srv->addr_list);      }      Dns_serve_channel(channel);      Dns_assign_channels();      srv->timeout_id = 0;      return FALSE;  /* Done! */   }   /* IP not already solved, keep on trying... */   return TRUE;}/* * CCC function for the DNS module * ( Data1 = hostname | IP; Data2 = {Not used here} ) */void a_Dns_ccc(int Op, int Branch, int Dir, ChainLink *Info,               void *Data1, void *Data2){   gchar *Hostname;   if ( Branch == 1 ){      if (Dir == BCK) {         /* Solve hostname */         switch (Op) {         case OpStart:            Hostname = g_strdup(Data1 ? (gchar *)Data1 : "");            Info->LocalKey = Hostname;            Dns_lookup(Info, Hostname);            break;         case OpAbort:            Dns_abort_by_ccc(Info);            g_free(Info->LocalKey);            g_free(Info);            break;         }      } else {  /* FWD */         /* Solve hostname answer */         switch (Op) {         case OpSend:            a_Chain_fcb(OpSend, Info, Data1, NULL);            break;         case OpEnd:            Hostname = Info->LocalKey;            a_Chain_fcb(OpEnd, Info, NULL, NULL);            g_free(Hostname);            break;         case OpAbort:            Hostname = Info->LocalKey;            a_Chain_fcb(OpAbort, Info, NULL, NULL);            g_free(Hostname);            break;         }      }   }}/* *  Dns memory-deallocation *  (Call this one at exit time) *  The Dns_queue is deallocated at execution time (no need to do that here) *  'dns_cache' is the only one that grows dinamically */void a_Dns_freeall(void){   gint i;   for ( i = 0; i < dns_cache_size; ++i ){      g_free(dns_cache[i].hostname);   }   g_free(dns_cache);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -