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); } }
static struct getdns_dict_item * getdns_dict_find_and_add(struct getdns_dict *dict, const char *key) { struct getdns_dict_item *item; item = (struct getdns_dict_item *) _getdns_rbtree_search(&(dict->root), key); if (!item) { /* add a node */ item = GETDNS_MALLOC(dict->mf, struct getdns_dict_item); item->node.key = _getdns_strdup(&dict->mf, key); item->data.n = 0; _getdns_rbtree_insert(&(dict->root), (_getdns_rbnode_t *) item); }
/** * private function used to locate a key in a dictionary * @param dict dicitonary to search * @param key key to search for * @return pointer to dictionary item, caller must not free storage associated with item * @return NULL if additnotfnd == FALSE and key is not in dictionary */ static struct getdns_dict_item * getdns_dict_find(const struct getdns_dict *dict, const char *key) { return (struct getdns_dict_item *) _getdns_rbtree_search((_getdns_rbtree_t *)&(dict->root), key); } /* getdns_dict_find */
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); } }