Exemplo n.º 1
0
Arquivo: looker.c Projeto: waruqi/tbox
/* //////////////////////////////////////////////////////////////////////////////////////
 * 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;
}
Exemplo n.º 2
0
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;
}
Exemplo n.º 3
0
/* //////////////////////////////////////////////////////////////////////////////////////
 * 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);
}