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

📄 dns.c

📁 SEP3203_DTU
💻 C
📖 第 1 页 / 共 2 页
字号:
  }

  return 0;
}

/**
 * dns_parse_name() - walk through a compact encoded DNS name and return the end 
 * of the name.
 */
static unsigned char *
dns_parse_name(unsigned char *query)
{
  unsigned char n;

  do {
    n = *query++;
    
    while(n > 0) {
      ++query;
      --n;
    };
  } while(*query != 0);

  return query + 1;
}

/**
 * dns_send
 */
static err_t
dns_send( char* name, u8_t id)
{ 
  struct dns_hdr *hdr;
  struct pbuf *p;
  char *query, *nptr, *pHostname;
  u8_t n;

  LWIP_DEBUGF(DNS_DEBUG, ("dns_send: \"%s\": request\n", name));

  /* if here, we have either a new query or a retry on a previous query to process */
  p = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dns_hdr)+DNS_MAX_NAME_LENGTH+sizeof(dns_endquery), PBUF_RAM);
  if (p) {
    hdr = (struct dns_hdr *)p->payload;
    memset(hdr, 0, sizeof(struct dns_hdr));
    hdr->id = htons(id);
    hdr->flags1 = DNS_FLAG1_RD;
    hdr->numquestions = htons(1);
    query = (char *)hdr + sizeof(struct dns_hdr);
    pHostname = name;
    --pHostname;
    /* convert hostname into suitable query format. */
    do {
      ++pHostname;
      nptr = query;
      ++query;
      for(n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) {
        *query = *pHostname;
        ++query;
        ++n;
      }
      *nptr = n;
    } while(*pHostname != 0);

    memcpy( query, dns_endquery, sizeof(dns_endquery));

    // resize pbuf to the exact dns query
    pbuf_realloc(p, (query+sizeof(dns_endquery))-((char*)(p->payload)));

    // send dns packet
    udp_send(dns_pcb, p);

    // free pbuf
    pbuf_free(p);

    return ERR_OK;
  }

  return ERR_BUF;
}

/**
 * dns_check_entries() - Runs through the list of names to see if there are any 
 * that have not yet been queried and, if so, sends out a query.
 */
static void
dns_check_entries(void)
{
  u8_t i;
  struct dns_table_entry *pEntry;

  for (i = 0; i < DNS_TABLE_SIZE; ++i) {
    pEntry = &dns_table[i];
    switch(pEntry->state) {

      case DNS_STATE_NEW:
      case DNS_STATE_ASKING: {
        if (pEntry->state == DNS_STATE_ASKING) {
          if (--pEntry->tmr == 0) {
            if (++pEntry->retries == DNS_MAX_RETRIES) {
              LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entries: \"%s\": timeout\n", pEntry->name));
              /* call specified callback function if provided */
              if (pEntry->found)
                (*pEntry->found)(pEntry->name, NULL, pEntry->arg);
              /* flush this entry */
              pEntry->state   = DNS_STATE_UNUSED;
              pEntry->found   = NULL;
              continue;
            }
            /* wait longer for the next retry */
            pEntry->tmr = pEntry->retries;
          } else {
            /* Its timer has not run out, so we move on to next entry. */
            continue;
          }
        } else {
          pEntry->state   = DNS_STATE_ASKING;
          pEntry->tmr     = 1;
          pEntry->retries = 0;
        }
        /* send DNS packet for this entry */
        dns_send(pEntry->name, i);
        break;
      }

      case DNS_STATE_DONE: {
        /* if the time to live is nul */
        if (--pEntry->ttl == 0) {
          LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entries: \"%s\": flush\n", pEntry->name));
          /* flush this entry */
          pEntry->state   = DNS_STATE_UNUSED;
          pEntry->found   = NULL;
        }
        break;
      }
    }
  }
}

/**
 * Callback for DNS responses
 */
static void
dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port)
{
  u8_t i;
  char *pHostname;
  struct dns_answer *ans;
  struct dns_hdr *hdr;
  struct dns_table_entry *pEntry;
  u8_t nquestions, nanswers;
  
  hdr = (struct dns_hdr *)p->payload;

  /* The ID in the DNS header should be our entry into the name table. */
  i = htons(hdr->id);
  pEntry = &dns_table[i];
  if( (i < DNS_TABLE_SIZE) && (pEntry->state == DNS_STATE_ASKING) ) {
    /* This entry is now completed. */
    pEntry->state = DNS_STATE_DONE;
    pEntry->ttl   = DNS_TTL_ENTRY;
    pEntry->err   = hdr->flags2 & DNS_FLAG2_ERR_MASK;

    /* Check for error. If so, call callback to inform. */
    if(pEntry->err != 0) {
      LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in flags\n", pEntry->name));
      /* call specified callback function if provided */
      if (pEntry->found)
        (*pEntry->found)(pEntry->name, NULL, pEntry->arg);
      /* flush this entry */
      pEntry->state   = DNS_STATE_UNUSED;
      pEntry->found   = NULL;
      return;
    }

    /* We only care about the question(s) and the answers. The authrr
       and the extrarr are simply discarded. */
    nquestions = htons(hdr->numquestions);
    nanswers   = htons(hdr->numanswers);

    /* Skip the name in the question. XXX: This should really be checked
       agains the name in the question, to be sure that they match. */
    pHostname = (char *) dns_parse_name((unsigned char *)p->payload + sizeof(struct dns_hdr)) + 4/*type(2)+class(2)*/;

    while(nanswers > 0) {
      /* The first byte in the answer resource record determines if it
         is a compressed record or a normal one. */
      if(*pHostname & 0xc0) {
        /* Compressed name. */
        pHostname +=2;
        /* printf("Compressed anwser\n");*/
      } else {
        /* Not compressed name. */
        pHostname = (char *) dns_parse_name((unsigned char *)pHostname);
      }

      ans = (struct dns_answer *)pHostname;
      /* printf("Answer: type %x, class %x, ttl %x, length %x\n",
         htons(ans->type), htons(ans->class), (htons(ans->ttl[0])
           << 16) | htons(ans->ttl[1]), htons(ans->len));*/

      /* Check for IP address type and Internet class. Others are discarded. */
      if((ntohs(ans->type) == DNS_RRTYPE_A) && (ntohs(ans->class) == DNS_RRCLASS_IN) && (ntohs(ans->len) == 4/*IPv4 address*/) ) {
        /* TODO: we should really check that this IP address is the one we want. */
        pEntry->ipaddr = ans->ipaddr;
        LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response = ", pEntry->name));
        ip_addr_debug_print(DNS_DEBUG, (&(pEntry->ipaddr)));
        LWIP_DEBUGF(DNS_DEBUG, ("\n"));
        /* call specified callback function if provided */
        if (pEntry->found)
          (*pEntry->found)(pEntry->name, &pEntry->ipaddr, pEntry->arg);
        return;
      } else {
        pHostname = pHostname + 10 + htons(ans->len);
      }
      --nanswers;
    }
    LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in response\n", pEntry->name));
  }
}

/**
 * Queues a name so that a question for the name will be sent out.
 * param name - The hostname that is to be queried.
 */
static void
dns_query(char *name, void (*found)(char *name, struct ip_addr *addr, void *arg), void *arg)
{
  u8_t i;
  u8_t lseq, lseqi;
  struct dns_table_entry *pEntry;

  /* search an unused entry, or the oldest one */
  lseq = lseqi = 0;
  for (i = 0; i < DNS_TABLE_SIZE; ++i) {
    pEntry = &dns_table[i];
    /* is it an unused entry ? */
    if (pEntry->state == DNS_STATE_UNUSED)
      break;

    /* check if this is the oldest entry used */
    if (dns_seqno - pEntry->seqno > lseq) {
      lseq = dns_seqno - pEntry->seqno;
      lseqi = i;
    }
  }

  /* if we don't have found an unused entry, use the oldest one */
  if (i == DNS_TABLE_SIZE) {
    i = lseqi;
    pEntry = &dns_table[i];
    /* since we replace the previous entry, we "unblock" the caller */
    LWIP_DEBUGF(DNS_DEBUG, ("dns_query: \"%s\": replaced by new entry\n", pEntry->name));
    /* call specified callback function if provided */
    if (pEntry->found) 
      (*pEntry->found)(pEntry->name, NULL, pEntry->arg);
  }

  /* fill the entry */
  strcpy(pEntry->name, name);
  pEntry->found = found;
  pEntry->arg   = arg;
  pEntry->state = DNS_STATE_NEW;
  pEntry->seqno = dns_seqno++;
}

/**
 * NON-BLOCKING callback version for use with raw API
 */
DNS_RESULT dns_gethostbyname(char *hostname, struct ip_addr *addr, 
                             void (*found)(char *name, struct ip_addr *ipaddr, void *arg),
                             void *arg
                             )
{
  /* not initialized or no valid server yet */
  if (dns_pcb == NULL) 
    return DNS_QUERY_INVALID;

  /* invalid hostname */
  if ((!hostname) || (!hostname[0]))
    return DNS_QUERY_INVALID;

  /* invalid hostname length */
  if (strlen(hostname) >= DNS_MAX_NAME_LENGTH)
    return DNS_QUERY_INVALID;

  /* host name already in octet notation? set ip addr and return COMPLETE */
  if ((addr->addr = inet_addr(hostname)) != INADDR_NONE)
    return DNS_COMPLETE;

  /* already have this address cached? */
  if ((addr->addr = dns_lookup(hostname)) != 0) 
    return DNS_COMPLETE;

  /* queue query with specified callback */
  dns_query(hostname, found, arg);

  /* force to send request */
  dns_check_entries();
  
  return DNS_QUERY_QUEUED;
}

#endif /* LWIP_DNS */

⌨️ 快捷键说明

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