static tb_bool_t tb_aicp_dns_reqt_func(tb_aice_ref_t aice) { // check tb_assert_and_check_return_val(aice && aice->aico && aice->code == TB_AICE_CODE_USEND, tb_false); // the aicp tb_aicp_ref_t aicp = (tb_aicp_ref_t)tb_aico_aicp(aice->aico); tb_assert_and_check_return_val(aicp, tb_false); // the impl tb_aicp_dns_impl_t* impl = (tb_aicp_dns_impl_t*)aice->priv; tb_assert_and_check_return_val(impl && impl->done.func, tb_false); // done tb_bool_t ok = tb_false; if (aice->state == TB_STATE_OK) { // trace tb_trace_d("reqt[%s]: aico: %p, server: %{ipaddr}, real: %lu", impl->host, impl->aico, &aice->u.usend.addr, aice->u.usend.real); // check tb_assert_and_check_return_val(aice->u.usend.real, tb_false); // post resp ok = tb_aico_urecv(aice->aico, impl->data, sizeof(impl->data), tb_aicp_dns_resp_func, (tb_pointer_t)impl); } // timeout or failed? else { // trace tb_trace_d("reqt[%s]: aico: %p, server: %{ipaddr}, state: %s", impl->host, impl->aico, &aice->u.usend.addr, tb_state_cstr(aice->state)); // the next server tb_ipaddr_ref_t server = &impl->list[impl->indx + 1]; if (!tb_ipaddr_is_empty(server)) { // indx++ impl->indx++; // init reqt tb_size_t size = tb_aicp_dns_reqt_init(impl); if (size) { // post reqt ok = tb_aico_usend(aice->aico, server, impl->data, size, tb_aicp_dns_reqt_func, (tb_pointer_t)impl); } } } // failed? done func if (!ok) impl->done.func((tb_aicp_dns_ref_t)impl, impl->host, tb_null, impl->done.priv); // continue return tb_true; }
static tb_long_t tb_aiop_spak_conn(tb_aiop_ptor_impl_t* impl, tb_aice_ref_t aice) { // check tb_assert_and_check_return_val(impl && aice, -1); tb_assert_and_check_return_val(aice->code == TB_AICE_CODE_CONN, -1); // the aico tb_aiop_aico_t* aico = (tb_aiop_aico_t*)aice->aico; tb_assert_and_check_return_val(aico && aico->base.handle, -1); // check address tb_assert(!tb_ipaddr_is_empty(&aice->u.conn.addr)); // try to connect it tb_long_t ok = tb_socket_connect(aico->base.handle, &aice->u.conn.addr); // trace tb_trace_d("conn[%p]: %{ipaddr}: %ld", aico, &aice->u.conn.addr, ok); // no connected? wait it if (!ok) { // wait it if (!aico->waiting) { // wait ok? if (tb_aiop_spak_wait(impl, aice)) return 0; // wait failed else aice->state = TB_STATE_FAILED; } // closed else aice->state = TB_STATE_FAILED; } // save it aice->state = ok > 0? TB_STATE_OK : TB_STATE_FAILED; // reset wait aico->waiting = 0; aico->aice.code = TB_AICE_CODE_NONE; // ok return 1; }
/* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ static tb_long_t tb_dns_looker_reqt(tb_dns_looker_t* looker) { // check tb_check_return_val(!(looker->step & TB_DNS_LOOKER_STEP_REQT), 1); // format it first if the request is null if (!tb_static_buffer_size(&looker->rpkt)) { // check size tb_assert_and_check_return_val(!looker->size, -1); // format query tb_static_stream_t stream; tb_byte_t rpkt[TB_DNS_RPKT_MAXN]; tb_size_t size = 0; tb_byte_t* p = tb_null; tb_static_stream_init(&stream, rpkt, TB_DNS_RPKT_MAXN); // identification number tb_static_stream_writ_u16_be(&stream, TB_DNS_HEADER_MAGIC); /* 0x2104: 0 0000 001 0000 0000 * * tb_uint16_t qr :1; // query/response flag * tb_uint16_t opcode :4; // purpose of message * tb_uint16_t aa :1; // authoritive answer * tb_uint16_t tc :1; // truncated message * tb_uint16_t rd :1; // recursion desired * tb_uint16_t ra :1; // recursion available * tb_uint16_t z :1; // its z! reserved * tb_uint16_t ad :1; // authenticated data * tb_uint16_t cd :1; // checking disabled * tb_uint16_t rcode :4; // response code * * this is a query * this is a standard query * not authoritive answer * not truncated * recursion desired * * recursion not available! hey we dont have it (lol) * */ #if 1 tb_static_stream_writ_u16_be(&stream, 0x0100); #else tb_static_stream_writ_u1(&stream, 0); // this is a query tb_static_stream_writ_ubits32(&stream, 0, 4); // this is a standard query tb_static_stream_writ_u1(&stream, 0); // not authoritive answer tb_static_stream_writ_u1(&stream, 0); // not truncated tb_static_stream_writ_u1(&stream, 1); // recursion desired tb_static_stream_writ_u1(&stream, 0); // recursion not available! hey we dont have it (lol) tb_static_stream_writ_u1(&stream, 0); tb_static_stream_writ_u1(&stream, 0); tb_static_stream_writ_u1(&stream, 0); tb_static_stream_writ_ubits32(&stream, 0, 4); #endif /* we have only one question * * tb_uint16_t question; // number of question entries * tb_uint16_t answer; // number of answer entries * tb_uint16_t authority; // number of authority entries * tb_uint16_t resource; // number of resource entries * */ tb_static_stream_writ_u16_be(&stream, 1); tb_static_stream_writ_u16_be(&stream, 0); tb_static_stream_writ_u16_be(&stream, 0); tb_static_stream_writ_u16_be(&stream, 0); // set questions, see as tb_dns_question_t // name + question1 + question2 + ... tb_static_stream_writ_u8(&stream, '.'); p = (tb_byte_t*)tb_static_stream_writ_cstr(&stream, tb_static_string_cstr(&looker->name)); // only one question now. tb_static_stream_writ_u16_be(&stream, 1); // we are requesting the ipv4 address tb_static_stream_writ_u16_be(&stream, 1); // it's internet (lol) // encode dns name if (!p || !tb_dns_encode_name((tb_char_t*)p - 1)) return -1; // size size = tb_static_stream_offset(&stream); tb_assert_and_check_return_val(size, -1); // copy tb_static_buffer_memncpy(&looker->rpkt, rpkt, size); } // data && size tb_byte_t const* data = tb_static_buffer_data(&looker->rpkt); tb_size_t size = tb_static_buffer_size(&looker->rpkt); // check tb_assert_and_check_return_val(data && size && looker->size < size, -1); // try get addr from the dns list tb_ipaddr_ref_t addr = tb_null; if (looker->maxn && looker->itor && looker->itor <= looker->maxn) addr = &looker->list[looker->itor - 1]; // check tb_assert_and_check_return_val(addr && !tb_ipaddr_is_empty(addr), -1); // family have been changed? reinit socket if (tb_ipaddr_family(addr) != looker->family) { // exit the previous socket if (looker->sock) tb_socket_exit(looker->sock); // init a new socket for the family looker->sock = tb_socket_init(TB_SOCKET_TYPE_UDP, tb_ipaddr_family(addr)); tb_assert_and_check_return_val(looker->sock, -1); // update the new family looker->family = (tb_uint8_t)tb_ipaddr_family(addr); } // need wait if no data looker->step &= ~TB_DNS_LOOKER_STEP_NEVT; // trace tb_trace_d("request: try %{ipaddr}", addr); // send request while (looker->size < size) { // writ data tb_long_t writ = tb_socket_usend(looker->sock, addr, data + looker->size, size - looker->size); tb_assert_and_check_return_val(writ >= 0, -1); // no data? if (!writ) { // abort? tb_check_return_val(!looker->size && !looker->tryn, -1); // tryn++ looker->tryn++; // continue return 0; } else looker->tryn = 0; // update size looker->size += writ; } // finish it looker->step |= TB_DNS_LOOKER_STEP_REQT; looker->tryn = 0; // reset rpkt looker->size = 0; tb_static_buffer_clear(&looker->rpkt); // ok tb_trace_d("request: ok"); return 1; }
tb_bool_t tb_aicp_dns_done(tb_aicp_dns_ref_t dns, tb_char_t const* host, tb_long_t timeout, tb_aicp_dns_done_func_t func, tb_cpointer_t priv) { // check tb_aicp_dns_impl_t* impl = (tb_aicp_dns_impl_t*)dns; tb_assert_and_check_return_val(impl && func && host && host[0], tb_false); // trace tb_trace_d("done: aico: %p, host: %s: ..", impl->aico, host); // init func impl->done.func = func; impl->done.priv = priv; // save host tb_strlcpy(impl->host, host, sizeof(impl->host)); // only address? ok tb_ipaddr_t addr = {0}; if (tb_ipaddr_ip_cstr_set(&addr, impl->host, TB_IPADDR_FAMILY_NONE)) { impl->done.func(dns, impl->host, &addr, impl->done.priv); return tb_true; } // try to lookup it from cache first if (tb_dns_cache_get(impl->host, &addr)) { impl->done.func(dns, impl->host, &addr, impl->done.priv); return tb_true; } // init server list if (!impl->size) impl->size = tb_dns_server_get(impl->list); tb_check_return_val(impl->size, tb_false); // get the server tb_ipaddr_ref_t server = &impl->list[impl->indx = 0]; tb_assert_and_check_return_val(!tb_ipaddr_is_empty(server), tb_false); // init reqt tb_size_t size = tb_aicp_dns_reqt_init(impl); tb_assert_and_check_return_val(size, tb_false); // init it first if no aico if (!impl->aico) { // init aico impl->aico = tb_aico_init(impl->aicp); tb_assert_and_check_return_val(impl->aico, tb_false); // open aico if (!tb_aico_open_sock_from_type(impl->aico, TB_SOCKET_TYPE_UDP, tb_ipaddr_family(server))) return tb_false; // init timeout tb_aico_timeout_set(impl->aico, TB_AICO_TIMEOUT_SEND, timeout); tb_aico_timeout_set(impl->aico, TB_AICO_TIMEOUT_RECV, timeout); } // post reqt return tb_aico_usend(impl->aico, server, impl->data, size, tb_aicp_dns_reqt_func, (tb_pointer_t)impl); }
static tb_bool_t tb_aicp_dns_resp_func(tb_aice_ref_t aice) { // check tb_assert_and_check_return_val(aice && aice->aico && aice->code == TB_AICE_CODE_URECV, tb_false); // the aicp tb_aicp_ref_t aicp = (tb_aicp_ref_t)tb_aico_aicp(aice->aico); tb_assert_and_check_return_val(aicp, tb_false); // the impl tb_aicp_dns_impl_t* impl = (tb_aicp_dns_impl_t*)aice->priv; tb_assert_and_check_return_val(impl, tb_false); // done tb_ipaddr_t addr = {0}; if (aice->state == TB_STATE_OK) { // trace tb_trace_d("resp[%s]: aico: %p, server: %{ipaddr}, real: %lu", impl->host, impl->aico, &aice->u.urecv.addr, aice->u.urecv.real); // check tb_assert_and_check_return_val(aice->u.urecv.real, tb_false); // done resp tb_aicp_dns_resp_done(impl, aice->u.urecv.real, &addr); } // timeout or failed? else { // trace tb_trace_d("resp[%s]: aico: %p, state: %s", impl->host, impl->aico, tb_state_cstr(aice->state)); } // ok or try to get ok from cache again if failed or timeout? tb_bool_t from_cache = tb_false; if (!tb_ipaddr_ip_is_empty(&addr) || (from_cache = tb_dns_cache_get(impl->host, &addr))) { // save to cache if (!from_cache) tb_dns_cache_set(impl->host, &addr); // done func impl->done.func((tb_aicp_dns_ref_t)impl, impl->host, &addr, impl->done.priv); return tb_true; } // try next server? tb_bool_t ok = tb_false; tb_ipaddr_ref_t server = &impl->list[impl->indx + 1]; if (!tb_ipaddr_is_empty(server)) { // indx++ impl->indx++; // init reqt tb_size_t size = tb_aicp_dns_reqt_init(impl); if (size) { // post reqt ok = tb_aico_usend(aice->aico, server, impl->data, size, tb_aicp_dns_reqt_func, (tb_pointer_t)impl); } } // failed? done func if (!ok) impl->done.func((tb_aicp_dns_ref_t)impl, impl->host, tb_null, impl->done.priv); // continue return tb_true; }