static void pico_dns_client_retransmission(unsigned long now, void *arg) { struct pico_dns_key *key = (struct pico_dns_key *)arg; struct pico_dns_ns *q_ns = NULL; if (!key->retrans) { dns_dbg("DNS: no retransmission!\n"); pico_free(key->q_hdr); if(pico_tree_delete(&DNSTable,key)) pico_free(key); } else if (key->retrans <= PICO_DNS_CLIENT_MAX_RETRANS) { key->retrans++; dns_dbg("DNS: retransmission! (%u attempts)\n", key->retrans); // ugly hack q_ns = pico_tree_next(pico_tree_findNode(&NSTable,&key->q_ns))->keyValue; if (q_ns) key->q_ns = *q_ns; else key->q_ns = *((struct pico_dns_ns *)pico_tree_first(&NSTable)); pico_dns_client_send(key); pico_timer_add(PICO_DNS_CLIENT_RETRANS, pico_dns_client_retransmission, key); } else { dns_dbg("DNS ERROR: no reply from nameservers! (%u attempts)\n", key->retrans); pico_socket_close(key->s); pico_err = PICO_ERR_EIO; key->callback(NULL, key->arg); pico_free(key->q_hdr); /* RB_REMOVE returns pointer to removed element, NULL to indicate error */ if(pico_tree_delete(&DNSTable,key)) pico_free(key); } }
static struct pico_dns_query *pico_dns_client_add_query(struct pico_dns_prefix *hdr, uint16_t len, struct pico_dns_query_suffix *suffix, void (*callback)(char *, void *), void *arg) { struct pico_dns_query *q = NULL, *found = NULL; q = pico_zalloc(sizeof(struct pico_dns_query)); if (!q) return NULL; q->query = (char *)hdr; q->len = len; q->id = short_be(hdr->id); q->qtype = short_be(suffix->qtype); q->qclass = short_be(suffix->qclass); q->retrans = 1; q->q_ns = *((struct pico_dns_ns *)pico_tree_first(&NSTable)); q->callback = callback; q->arg = arg; q->s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dns_client_callback); if (!q->s) { pico_free(q); return NULL; } found = pico_tree_insert(&DNSTable, q); if (found) { pico_err = PICO_ERR_EAGAIN; pico_socket_close(q->s); pico_free(q); return NULL; } return q; }
static struct pico_dns_ns pico_dns_client_next_ns(struct pico_ip4 *ns_addr) { struct pico_dns_ns dns = {{0}}, *nxtdns = NULL; struct pico_tree_node *node = NULL, *nxtnode = NULL; dns.ns = *ns_addr; node = pico_tree_findNode(&NSTable, &dns); if (!node) return dns; /* keep using current NS */ nxtnode = pico_tree_next(node); nxtdns = nxtnode->keyValue; if (!nxtdns) nxtdns = (struct pico_dns_ns *)pico_tree_first(&NSTable); return *nxtdns; }
int pico_dns_client_nameserver(struct pico_ip4 *ns, uint8_t flag) { struct pico_dns_ns test, *key = NULL; if (!ns) { pico_err = PICO_ERR_EINVAL; return -1; } switch (flag) { case PICO_DNS_NS_ADD: key = pico_zalloc(sizeof(struct pico_dns_ns)); if (!key) { pico_err = PICO_ERR_ENOMEM; return -1; } key->ns = *ns; if(pico_tree_insert(&NSTable,key)){ dns_dbg("DNS WARNING: nameserver %08X already added\n",ns->addr); pico_err = PICO_ERR_EINVAL; pico_free(key); return -1; /* Element key already exists */ } dns_dbg("DNS: nameserver %08X added\n", ns->addr); /* If default NS found, remove it */ pico_string_to_ipv4(PICO_DNS_NS_GOOGLE, &test.ns.addr); if (ns->addr != test.ns.addr) { key = pico_tree_findKey(&NSTable,&test); if (key) { if(pico_tree_delete(&NSTable,key)) { dns_dbg("DNS: default nameserver %08X removed\n", test.ns.addr); pico_free(key); } else { pico_err = PICO_ERR_EAGAIN; return -1; } } } break; case PICO_DNS_NS_DEL: test.ns = *ns; key = pico_tree_findKey(&NSTable,&test); if (!key) { dns_dbg("DNS WARNING: nameserver %08X not found\n", ns->addr); pico_err = PICO_ERR_EINVAL; return -1; } /* RB_REMOVE returns pointer to removed element, NULL to indicate error */ if(pico_tree_delete(&NSTable,key)) { dns_dbg("DNS: nameserver %08X removed\n",key->ns.addr); pico_free(key); } else { pico_err = PICO_ERR_EAGAIN; return -1; } /* If no NS left, add default NS */ if(pico_tree_first(&NSTable) == NULL){ dns_dbg("DNS: add default nameserver\n"); return pico_dns_client_init(); } break; default: pico_err = PICO_ERR_EINVAL; return -1; } return 0; }