/* ////////////////////////////////////////////////////////////////////////////////////// * 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_long_t tb_filter_spak(tb_filter_ref_t self, tb_byte_t const* data, tb_size_t size, tb_byte_t const** pdata, tb_size_t need, tb_long_t sync) { // check tb_filter_t* filter = (tb_filter_t*)self; tb_assert_and_check_return_val(filter && filter->spak && pdata, -1); // init odata *pdata = tb_null; // save the input offset filter->offset += size; // eof? if (filter->limit >= 0 && filter->offset == filter->limit) filter->beof = tb_true; // eof? sync it if (filter->beof) sync = -1; // the idata tb_byte_t const* idata = tb_buffer_data(&filter->idata); tb_size_t isize = tb_buffer_size(&filter->idata); if (data && size) { // append data to cache if have the cache data if (idata && isize) { // trace tb_trace_d("[%p]: append idata: %lu", self, size); // append data idata = tb_buffer_memncat(&filter->idata, data, size); isize = tb_buffer_size(&filter->idata); } // using the data directly if no cache data else { // trace tb_trace_d("[%p]: using idata directly: %lu", self, size); // using it directly idata = data; isize = size; } } // sync data if null else { // check sync tb_assert_and_check_return_val(sync, 0); } // the need if (!need) need = tb_max(size, tb_queue_buffer_maxn(&filter->odata)); tb_assert_and_check_return_val(need, -1); // init pull tb_size_t omaxn = 0; tb_byte_t* odata = tb_queue_buffer_pull_init(&filter->odata, &omaxn); if (odata) { // the osize tb_long_t osize = omaxn >= need? need : 0; // exit pull if (odata) tb_queue_buffer_pull_exit(&filter->odata, osize > 0? osize : 0); // enough? if (osize > 0) { // append to the cache if idata is not belong to the cache if (size && idata == data) tb_buffer_memncat(&filter->idata, data, size); // return it directly *pdata = odata; return osize; } } // grow odata maxn if not enough if (need > tb_queue_buffer_maxn(&filter->odata)) tb_queue_buffer_resize(&filter->odata, need); // the odata omaxn = 0; odata = tb_queue_buffer_push_init(&filter->odata, &omaxn); tb_assert_and_check_return_val(odata && omaxn, -1); // init stream tb_static_stream_t istream = {0}; tb_static_stream_t ostream = {0}; if (idata && isize) { // @note istream maybe null for sync the end data if (!tb_static_stream_init(&istream, (tb_byte_t*)idata, isize)) return -1; } if (!tb_static_stream_init(&ostream, (tb_byte_t*)odata, omaxn)) return -1; // trace tb_trace_d("[%p]: spak: ileft: %lu, oleft: %lu, offset: %llu, limit: %lld, beof: %d: ..", self, tb_buffer_size(&filter->idata), tb_queue_buffer_size(&filter->odata), filter->offset, filter->limit, filter->beof); // spak data tb_long_t osize = filter->spak(filter, &istream, &ostream, sync); // eof? if (osize < 0) filter->beof = tb_true; // no data and eof? if (!osize && !tb_static_stream_left(&istream) && filter->beof) osize = -1; // eof? sync it if (filter->beof) sync = -1; // exit odata tb_queue_buffer_push_exit(&filter->odata, osize > 0? osize : 0); // have the left idata? tb_size_t left = tb_static_stream_left(&istream); if (left) { // move to the cache head if idata is belong to the cache if (idata != data) { // trace tb_trace_d("[%p]: move to the cache head: %lu", self, left); tb_buffer_memnmov(&filter->idata, tb_static_stream_offset(&istream), left); } // append to the cache if idata is not belong to the cache else { // trace tb_trace_d("[%p]: append to the cache: %lu", self, left); tb_buffer_memncat(&filter->idata, tb_static_stream_pos(&istream), left); } } // clear the cache else tb_buffer_clear(&filter->idata); // init pull omaxn = 0; odata = tb_queue_buffer_pull_init(&filter->odata, &omaxn); // no sync? cache the output data if (!sync) osize = omaxn >= need? need : 0; // sync and has data? return it directly else if (omaxn) osize = tb_min(omaxn, need); // sync, no data or end? // else osize = osize; // exit pull if (odata) tb_queue_buffer_pull_exit(&filter->odata, osize > 0? osize : 0); // return it if have the odata if (osize > 0) *pdata = odata; // trace tb_trace_d("[%p]: spak: ileft: %lu, oleft: %lu, offset: %llu, limit: %lld, beof: %d: %ld", self, tb_buffer_size(&filter->idata), tb_queue_buffer_size(&filter->odata), filter->offset, filter->limit, filter->beof, osize); // ok? return osize; }
/* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_size_t tb_aicp_dns_reqt_init(tb_aicp_dns_impl_t* impl) { // check tb_assert_and_check_return_val(impl, 0); // init query data tb_static_stream_t stream; tb_static_stream_init(&stream, impl->data, 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, '.'); tb_char_t* p = tb_static_stream_writ_cstr(&stream, impl->host); // only one question now. tb_static_stream_writ_u16_be(&stream, 1); // we are requesting the ipv4 dnsess tb_static_stream_writ_u16_be(&stream, 1); // it's internet (lol) // encode impl name if (!p || !tb_dns_encode_name(p - 1)) return 0; // ok? return tb_static_stream_offset(&stream); }