void dns_req_free(getdns_dns_req * req) { if (!req) { return; } getdns_network_req *net_req = NULL; struct getdns_context *context = req->context; /* free extensions */ getdns_dict_destroy(req->extensions); /* free network requests */ net_req = req->first_req; while (net_req) { getdns_network_req *next = net_req->next; network_req_free(net_req); net_req = next; } if (req->local_timeout_id != 0) { getdns_context_clear_timeout(context, req->local_timeout_id); } getdns_context_clear_timeout(context, req->trans_id); /* free strduped name */ GETDNS_FREE(req->my_mf, req->name); GETDNS_FREE(req->my_mf, req); }
getdns_return_t getdns_rr_dict2str_scan( const getdns_dict *rr_dict, char **str, int *str_len) { getdns_return_t r; gldns_buffer gbuf; uint8_t buf_spc[4096], *buf = buf_spc, *scan_buf; size_t sz, scan_sz; int prev_str_len; char *prev_str; int sz_needed; if (!rr_dict || !str || !*str || !str_len) return GETDNS_RETURN_INVALID_PARAMETER; gldns_buffer_init_frm_data(&gbuf, buf, sizeof(buf_spc)); r = _getdns_rr_dict2wire(rr_dict, &gbuf); if (gldns_buffer_position(&gbuf) > sizeof(buf_spc)) { if (!(buf = GETDNS_XMALLOC( rr_dict->mf, uint8_t, (sz = gldns_buffer_position(&gbuf))))) { return GETDNS_RETURN_MEMORY_ERROR; } gldns_buffer_init_frm_data(&gbuf, buf, sz); r = _getdns_rr_dict2wire(rr_dict, &gbuf); } if (r) { if (buf != buf_spc) GETDNS_FREE(rr_dict->mf, buf); return r; } scan_buf = gldns_buffer_begin(&gbuf); scan_sz = gldns_buffer_position(&gbuf); prev_str = *str; prev_str_len = *str_len; sz = (size_t)*str_len; sz_needed = gldns_wire2str_rr_scan( &scan_buf, &scan_sz, str, &sz, NULL, 0); if (sz_needed > prev_str_len) { *str = prev_str + sz_needed; *str_len = prev_str_len - sz_needed; r = GETDNS_RETURN_NEED_MORE_SPACE; } else { *str_len = sz; **str = 0; } if (buf != buf_spc) GETDNS_FREE(rr_dict->mf, buf); return r; }
static void tcp_connection_destroy(tcp_connection *conn) { struct mem_funcs *mf; getdns_eventloop *loop; tcp_to_write *cur, *next; mf = &conn->super.l->set->context->mf; if (getdns_context_get_eventloop(conn->super.l->set->context, &loop)) return; if (conn->event.ev) loop->vmt->clear(loop, &conn->event); if (conn->event.read_cb||conn->event.write_cb||conn->event.timeout_cb) { conn->event.read_cb = conn->event.write_cb = conn->event.timeout_cb = NULL; } if (conn->fd >= 0) { (void) _getdns_closesocket(conn->fd); conn->fd = -1; } if (conn->read_buf) { GETDNS_FREE(*mf, conn->read_buf); conn->read_buf = conn->read_pos = NULL; conn->to_read = 0; } if ((cur = conn->to_write)) { while (cur) { next = cur->next; GETDNS_FREE(*mf, cur); cur = next; } conn->to_write = NULL; } if (conn->to_answer > 0) return; /* Unlink this connection */ (void) _getdns_rbtree_delete( &conn->super.l->set->connections_set, conn); DEBUG_SERVER("[connection del] count: %d\n", (int)conn->super.l->set->connections_set.count); if ((*conn->super.prev_next = conn->super.next)) conn->super.next->prev_next = conn->super.prev_next; free_listen_set_when_done(conn->super.l->set); GETDNS_FREE(*mf, conn); }
/*---------------------------------------- getdns_list_destroy */ void getdns_list_destroy(struct getdns_list *list) { size_t i; if (!list) return; for (i = 0; i < list->numinuse; i++) _getdns_list_destroy_item(list, i); if (list->items) GETDNS_FREE(list->mf, list->items); GETDNS_FREE(list->mf, list); } /* getdns_list_destroy */
static void _getdns_cancel_reply(getdns_context *context, connection *conn) { struct mem_funcs *mf; if (!conn) return; if (context && context->server && _getdns_rbtree_search(&context->server->connections_set, conn) != &conn->super) return; if (conn->l->transport == GETDNS_TRANSPORT_TCP) { tcp_connection *tcp_conn = (tcp_connection *)conn; if (tcp_conn->to_answer > 0 && --tcp_conn->to_answer == 0 && tcp_conn->fd == -1) tcp_connection_destroy(tcp_conn); } else if (conn->l->transport == GETDNS_TRANSPORT_UDP && (mf = &conn->l->set->context->mf)) { listen_set *set = conn->l->set; /* Unlink this connection */ (void) _getdns_rbtree_delete( &set->connections_set, conn); DEBUG_SERVER("[connection del] count: %d\n", (int)set->connections_set.count); if ((*conn->prev_next = conn->next)) conn->next->prev_next = conn->prev_next; GETDNS_FREE(*mf, conn); free_listen_set_when_done(set); } }
getdns_return_t _getdns_fp2rr_list(struct mem_funcs *mf, FILE *in, getdns_list **rr_list, const char *origin, uint32_t default_ttl) { struct gldns_file_parse_state pst; getdns_list *rrs; getdns_return_t r = GETDNS_RETURN_GOOD; uint8_t *rr; size_t len, dname_len; getdns_dict *rr_dict; if (!in || !rr_list) return GETDNS_RETURN_INVALID_PARAMETER; if (!origin) { *pst.origin = 0; pst.origin_len = 1; } else if (gldns_str2wire_dname_buf(origin,pst.origin,&pst.origin_len)) return GETDNS_RETURN_GENERIC_ERROR; *pst.prev_rr = 0; pst.prev_rr_len = 1; pst.default_ttl = default_ttl; pst.lineno = 1; if (!(rrs = _getdns_list_create_with_mf(mf))) return GETDNS_RETURN_MEMORY_ERROR; if (!(rr = GETDNS_XMALLOC(*mf, uint8_t, GLDNS_RR_BUF_SIZE))) r = GETDNS_RETURN_MEMORY_ERROR; else while (r == GETDNS_RETURN_GOOD && !feof(in)) { len = GLDNS_RR_BUF_SIZE; dname_len = 0; if (gldns_fp2wire_rr_buf(in, rr, &len, &dname_len, &pst)) break; if (dname_len && dname_len < sizeof(pst.prev_rr)) { memcpy(pst.prev_rr, rr, dname_len); pst.prev_rr_len = dname_len; } if (len == 0) continue; if ((r = _getdns_wire2rr_dict(mf, rr, len, &rr_dict))) break; r = _getdns_list_append_dict(rrs, rr_dict); getdns_dict_destroy(rr_dict); } if (rr) GETDNS_FREE(*mf, rr); if (r) getdns_list_destroy(rrs); else *rr_list = rrs; return r; }
static void tcp_write_cb(void *userarg) { tcp_connection *conn = (tcp_connection *)userarg; struct mem_funcs *mf; getdns_eventloop *loop; tcp_to_write *to_write; ssize_t written; assert(userarg); if (!(mf = &conn->super.l->set->context->mf)) return; if (getdns_context_get_eventloop(conn->super.l->set->context, &loop)) return; /* Reset tcp_connection idle timeout */ loop->vmt->clear(loop, &conn->event); if (!conn->to_write) { conn->event.write_cb = NULL; (void) loop->vmt->schedule(loop, conn->fd, DOWNSTREAM_IDLE_TIMEOUT, &conn->event); return; } to_write = conn->to_write; if (conn->fd == -1 || (written = send(conn->fd, (const void *)&to_write->write_buf[to_write->written], to_write->write_buf_len - to_write->written, 0)) == -1) { if (conn->fd != -1) { if (_getdns_socketerror_wants_retry()) { (void) loop->vmt->schedule(loop, conn->fd, DOWNSTREAM_IDLE_TIMEOUT, &conn->event); return; } DEBUG_SERVER("I/O error from send(): %s\n", _getdns_errnostr()); } /* IO error, close connection */ tcp_connection_destroy(conn); return; } to_write->written += written; if (to_write->written == to_write->write_buf_len) { conn->to_write = to_write->next; GETDNS_FREE(*mf, to_write); } if (!conn->to_write) conn->event.write_cb = NULL; (void) loop->vmt->schedule(loop, conn->fd, DOWNSTREAM_IDLE_TIMEOUT, &conn->event); }
void network_req_free(getdns_network_req * net_req) { if (!net_req) { return; } if (net_req->result) { ldns_pkt_free(net_req->result); } GETDNS_FREE(net_req->owner->my_mf, net_req); }
getdns_return_t _getdns_str2rr_dict(struct mem_funcs *mf, const char *str, getdns_dict **rr_dict, const char *origin, uint32_t default_ttl) { uint8_t wire_spc[4096], *wire = wire_spc; uint8_t origin_spc[256], *origin_wf; size_t origin_len = sizeof(origin_spc), wire_len = sizeof(wire_spc); int e; getdns_return_t r; if (!str || !rr_dict) return GETDNS_RETURN_INVALID_PARAMETER; if (!origin) origin_wf = NULL; else if (gldns_str2wire_dname_buf(origin, origin_spc, &origin_len)) return GETDNS_RETURN_GENERIC_ERROR; else origin_wf = origin_spc; e = gldns_str2wire_rr_buf(str, wire, &wire_len, NULL, default_ttl, origin_wf, origin_len, NULL, 0); if (GLDNS_WIREPARSE_ERROR(e) == GLDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL) { if (!(wire = GETDNS_XMALLOC( *mf, uint8_t, (wire_len = GLDNS_RR_BUF_SIZE)))) return GETDNS_RETURN_MEMORY_ERROR; e = gldns_str2wire_rr_buf(str, wire, &wire_len, NULL, default_ttl, origin_wf, origin_len, NULL, 0); } if (e) { if (wire != wire_spc) GETDNS_FREE(*mf, wire); return GETDNS_RETURN_GENERIC_ERROR; } r = _getdns_wire2rr_dict(mf, wire, wire_len, rr_dict); if (wire != wire_spc) GETDNS_FREE(*mf, wire); return r; }
getdns_return_t _getdns_get_pubkey_pinset_from_list(const getdns_list *pinset_list, struct mem_funcs *mf, sha256_pin_t **pinset_out) { getdns_return_t r; size_t pins, i; sha256_pin_t *out = NULL, *onext = NULL; getdns_dict * pin; getdns_bindata * data = NULL; if (r = getdns_list_get_length(pinset_list, &pins), r) return r; for (i = 0; i < pins; i++) { if (r = getdns_list_get_dict(pinset_list, i, &pin), r) goto fail; /* does the pin have the right digest type? */ if (r = getdns_dict_get_bindata(pin, "digest", &data), r) goto fail; if (data->size != sha256.size || memcmp(data->data, sha256.data, sha256.size)) { r = GETDNS_RETURN_INVALID_PARAMETER; goto fail; } /* if it does, is the value the right length? */ if (r = getdns_dict_get_bindata(pin, "value", &data), r) goto fail; if (data->size != SHA256_DIGEST_LENGTH) { r = GETDNS_RETURN_INVALID_PARAMETER; goto fail; } /* make a new pin */ onext = GETDNS_MALLOC(*mf, sha256_pin_t); if (onext == NULL) { r = GETDNS_RETURN_MEMORY_ERROR; goto fail; } onext->next = out; memcpy(onext->pin, data->data, SHA256_DIGEST_LENGTH); out = onext; } *pinset_out = out; return GETDNS_RETURN_GOOD; fail: while (out) { onext = out->next; GETDNS_FREE(*mf, out); out = onext; } return r; }
static void getdns_libuv_close_cb(uv_handle_t *handle) { poll_timer *my_ev = (poll_timer *)handle->data; DEBUG_UV("enter libuv_close_cb(el_ev->ev = %p, to_close = %d)\n" , my_ev, my_ev->to_close); if (--my_ev->to_close) { DEBUG_UV( "exit libuv_close_cb(el_ev->ev = %p, to_close = %d)\n" , my_ev, my_ev->to_close); return; } DEBUG_UV("enter libuv_close_cb to_free: %p\n", my_ev); GETDNS_FREE(my_ev->mf, my_ev); DEBUG_UV("enter libuv_close_cb freed: %p\n", my_ev); }
struct getdns_list * getdns_list_create_with_extended_memory_functions( void *userarg, void *(*malloc)(void *userarg, size_t), void *(*realloc)(void *userarg, void *, size_t), void (*free)(void *userarg, void *)) { struct getdns_list *list; mf_union mf; if (!malloc || !realloc || !free) return NULL; mf.ext.malloc = malloc; list = userarg == MF_PLAIN ? (struct getdns_list *)(*mf.pln.malloc)( sizeof(struct getdns_list)) : (struct getdns_list *)(*mf.ext.malloc)(userarg, sizeof(struct getdns_list)); if (!list) return NULL; list->mf.mf_arg = userarg; list->mf.mf.ext.malloc = malloc; list->mf.mf.ext.realloc = realloc; list->mf.mf.ext.free = free; list->numinuse = 0; if (!(list->items = GETDNS_XMALLOC( list->mf, getdns_item, GETDNS_LIST_BLOCKSZ))) { GETDNS_FREE(list->mf, list); return NULL; } list->numalloc = GETDNS_LIST_BLOCKSZ; return list; }
getdns_return_t getdns_reply(getdns_context *context, const getdns_dict *reply, getdns_transaction_t request_id) { /* TODO: Check request_id at context->outbound_requests */ connection *conn = (connection *)(intptr_t)request_id; struct mem_funcs *mf; getdns_eventloop *loop; uint8_t buf[65536]; size_t len; getdns_return_t r; if (!conn) return GETDNS_RETURN_INVALID_PARAMETER; if (!context || !context->server) { if (!context) context = conn->l->set->context; } else if (_getdns_rbtree_search(&context->server->connections_set, conn) != &conn->super) return GETDNS_RETURN_NO_SUCH_LIST_ITEM; if (!reply) { _getdns_cancel_reply(context, conn); return GETDNS_RETURN_GOOD; } if (!(mf = &conn->l->set->context->mf)) return GETDNS_RETURN_GENERIC_ERROR;; if ((r = getdns_context_get_eventloop(conn->l->set->context, &loop))) return r; len = sizeof(buf); if ((r = getdns_msg_dict2wire_buf(reply, buf, &len))) return r; else if (conn->l->transport == GETDNS_TRANSPORT_UDP) { listener *l = conn->l; if (conn->l->fd >= 0 && sendto(conn->l->fd, (void *)buf, len, 0, (struct sockaddr *)&conn->remote_in, conn->addrlen) == -1) { /* TODO: handle _getdns_socketerror_wants_retry() */ /* IO error, never cleanup a listener because of I/O error */ DEBUG_SERVER("I/O error from sendto(): %s\n", _getdns_errnostr()); } /* Unlink this connection */ (void) _getdns_rbtree_delete( &l->set->connections_set, conn); DEBUG_SERVER("[connection del] count: %d\n", (int)l->set->connections_set.count); if ((*conn->prev_next = conn->next)) conn->next->prev_next = conn->prev_next; GETDNS_FREE(*mf, conn); if (l->fd < 0) free_listen_set_when_done(l->set); } else if (conn->l->transport == GETDNS_TRANSPORT_TCP) { tcp_connection *conn = (tcp_connection *)(intptr_t)request_id; tcp_to_write **to_write_p; tcp_to_write *to_write; if (conn->fd == -1) { if (conn->to_answer > 0) --conn->to_answer; tcp_connection_destroy(conn); return GETDNS_RETURN_GOOD; } if (!(to_write = (tcp_to_write *)GETDNS_XMALLOC( *mf, uint8_t, sizeof(tcp_to_write) + len + 2))) { tcp_connection_destroy(conn); return GETDNS_RETURN_MEMORY_ERROR; } to_write->write_buf_len = len + 2; to_write->write_buf[0] = (len >> 8) & 0xFF; to_write->write_buf[1] = len & 0xFF; to_write->written = 0; to_write->next = NULL; (void) memcpy(to_write->write_buf + 2, buf, len); /* Append to_write to conn->to_write list */ for ( to_write_p = &conn->to_write ; *to_write_p ; to_write_p = &(*to_write_p)->next) ; /* pass */ *to_write_p = to_write; if (conn->to_answer > 0) conn->to_answer--; /* When event is scheduled, and doesn't have tcp_write_cb: * reschedule. */ if (conn->event.write_cb == NULL) { if (conn->event.ev) loop->vmt->clear(loop, &conn->event); conn->event.write_cb = tcp_write_cb; (void) loop->vmt->schedule(loop, conn->fd, DOWNSTREAM_IDLE_TIMEOUT, &conn->event); } }
static void getdns_libevent_cleanup(getdns_eventloop *loop) { getdns_libevent *ext = (getdns_libevent *)loop; GETDNS_FREE(ext->mf, ext); }