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 int pico_dns_client_del_query(uint16_t id) { struct pico_dns_query test = { 0 }, *found = NULL; test.id = id; found = pico_tree_findKey(&DNSTable, &test); if (!found) return -1; pico_free(found->query); pico_socket_close(found->s); pico_tree_delete(&DNSTable, found); pico_free(found); return 0; }
static int pico_dhcp_client_del_cookie(uint32_t xid) { struct pico_dhcp_client_cookie test = { 0 }, *found = NULL; test.xid = xid; found = pico_tree_findKey(&DHCPCookies, &test); if (!found) return -1; pico_socket_close(found->s); pico_ipv4_link_del(found->dev, found->address); pico_tree_delete(&DHCPCookies, found); pico_free(found); return 0; }
void cb_tcpclient(uint16_t ev, struct pico_socket *s) { static int w_size = 0; static int r_size = 0; static int closed = 0; int r, w; char buf[1024]; ZF_LOGD("tcpclient> wakeup %lu, event %u\n", count, ev); if (ev & PICO_SOCK_EV_RD) { do { r = pico_socket_read(s, buf, 1024); if (r > 0) { printf("READ >>"); fwrite(buf, r, 1, stdout); } if (r < 0){ ZF_LOGF("READ ERROR\n"); } } while(r > 0); } if (ev & PICO_SOCK_EV_CONN) { ZF_LOGD("Connection established with server.\n"); } if (ev & PICO_SOCK_EV_FIN) { ZF_LOGD("Socket closed. Exit normally. \n"); } if (ev & PICO_SOCK_EV_ERR) { ZF_LOGD("Socket error received: %s. Bailing out.\n", strerror(pico_err)); } if (ev & PICO_SOCK_EV_CLOSE) { ZF_LOGD("Socket received close from peer - Wrong case if not all client data sent!\n"); pico_socket_close(s); } if (ev & PICO_SOCK_EV_WR) { ZF_LOGD("Pico socket write cb\n"); } }
static void pico_dns_client_callback(uint16_t ev, struct pico_socket *s) { char *q_qname, *q_suf, *a_hdr, *a_qname, *a_suf, *a_rdata; struct dns_message_hdr *hdr; struct dns_query_suffix query_suf; struct dns_answer_suffix answer_suf; struct pico_dns_key test, *key; char *answer; char dns_answer[PICO_DNS_MAX_RESPONSE_LEN] = {0}; uint8_t valid_suffix = 0; uint16_t compression = 0; int i = 0, r = 0; if (ev & PICO_SOCK_EV_RD) { r = pico_socket_read(s, dns_answer, PICO_DNS_MAX_RESPONSE_LEN); pico_socket_close(s); if (r == PICO_DNS_MAX_RESPONSE_LEN || r < (int)sizeof(struct dns_message_hdr)) { dns_dbg("DNS ERROR: received incorrect number(%d) of bytes\n", r); return; } /* Check header validity */ a_hdr = dns_answer; hdr = (struct dns_message_hdr *) a_hdr; pico_dns_client_hdr_ntoh(hdr); if (GET_FLAG_QR(hdr) != PICO_DNS_QR_RESPONSE || GET_FLAG_OPCODE(hdr) != PICO_DNS_OPCODE_QUERY || GET_FLAG_TC(hdr) == PICO_DNS_TC_IS_TRUNCATED || GET_FLAG_RCODE(hdr) != PICO_DNS_RCODE_NO_ERROR) { dns_dbg("DNS ERROR: OPCODE %d | TC %d | RCODE %d\n", GET_FLAG_OPCODE(hdr), GET_FLAG_TC(hdr), GET_FLAG_RCODE(hdr)); return; } if (hdr->ancount < 1 || r < (int)(sizeof(struct dns_message_hdr) + hdr->qdcount * sizeof(struct dns_query_suffix) + hdr->ancount * sizeof(struct dns_answer_suffix))) { dns_dbg("DNS ERROR: ancount < 1 OR received number(%d) of bytes too low\n", r); return; } /* Find DNS key */ test.id = hdr->id; key = pico_tree_findKey(&DNSTable,&test); if (!key) { dns_dbg("DNS WARNING: key with id %u not found\n", hdr->id); return; } key->retrans = 0; /* Check query suffix validity */ q_qname = a_hdr + sizeof(struct dns_message_hdr); q_suf = pico_dns_client_seek(q_qname); query_suf = *(struct dns_query_suffix *) q_suf; if (short_be(query_suf.qtype) != key->qtype || short_be(query_suf.qclass) != key->qclass) { dns_dbg("DNS ERROR: received qtype (%u) or qclass (%u) incorrect\n", short_be(query_suf.qtype), short_be(query_suf.qclass)); return; } /* Seek answer suffix */ a_qname = q_suf + sizeof(struct dns_query_suffix); a_suf = a_qname; while(i++ < hdr->ancount) { uint16_t comp_h = short_from(a_suf); compression = short_be(comp_h); switch (compression >> 14) { case PICO_DNS_POINTER: while (compression >> 14 == PICO_DNS_POINTER) { dns_dbg("DNS: pointer\n"); a_suf += sizeof(uint16_t); comp_h = short_from(a_suf); compression = short_be(comp_h); } break; case PICO_DNS_LABEL: dns_dbg("DNS: label\n"); a_suf = pico_dns_client_seek(a_qname); break; default: dns_dbg("DNS ERROR: incorrect compression (%u) value\n", compression); return; } /* Check answer suffix validity */ answer_suf = *(struct dns_answer_suffix *)a_suf; if (short_be(answer_suf.qtype) != key->qtype || short_be(answer_suf.qclass) != key->qclass) { dns_dbg("DNS WARNING: received qtype (%u) or qclass (%u) incorrect\n", short_be(answer_suf.qtype), short_be(answer_suf.qclass)); a_suf = a_suf + sizeof(struct dns_answer_suffix) + short_be(answer_suf.rdlength); continue; } if (short_be(answer_suf.ttl) > PICO_DNS_MAX_TTL) { dns_dbg("DNS WARNING: received TTL (%u) > MAX (%u)\n", short_be(answer_suf.ttl), PICO_DNS_MAX_TTL); a_suf = a_suf + sizeof(struct dns_answer_suffix) + short_be(answer_suf.rdlength); continue; } valid_suffix = 1; break; } if (!valid_suffix) { dns_dbg("DNS ERROR: invalid dns answer suffix\n"); return; } a_rdata = a_suf + sizeof(struct dns_answer_suffix); if (key->qtype == PICO_DNS_TYPE_A) { uint32_t ip_h = long_from(a_rdata); dns_dbg("DNS: length %u | ip %08X\n", short_be(answer_suf.rdlength), long_be(ip_h)); answer = pico_zalloc(16); pico_ipv4_to_string(answer, ip_h); key->callback(answer, key->arg); } else if (key->qtype == PICO_DNS_TYPE_PTR) { pico_dns_client_reverse_label((char *) a_rdata); dns_dbg("DNS: length %u | name %s\n", short_be(answer_suf.rdlength), (char *)a_rdata + 1); answer = pico_zalloc(answer_suf.rdlength - 1); memcpy(answer, (char *)a_rdata + 1, short_be(answer_suf.rdlength) - 1); key->callback(answer, key->arg); } else { dns_dbg("DNS ERROR: incorrect qtype (%u)\n", key->qtype); return; } }