separated dnc code from dns.c to dns-cli.c
This commit is contained in:
		@ -36,6 +36,7 @@ include_HEADERS = \
 | 
			
		||||
lib_LTLIBRARIES = libmio.la
 | 
			
		||||
libmio_la_SOURCES = \
 | 
			
		||||
	dns.c \
 | 
			
		||||
	dns-cli.c \
 | 
			
		||||
	err.c \
 | 
			
		||||
	fmt.c \
 | 
			
		||||
	fmt-imp.h \
 | 
			
		||||
 | 
			
		||||
@ -138,12 +138,13 @@ am__DEPENDENCIES_1 =
 | 
			
		||||
am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1)
 | 
			
		||||
libmio_la_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \
 | 
			
		||||
	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
 | 
			
		||||
am_libmio_la_OBJECTS = libmio_la-dns.lo libmio_la-err.lo \
 | 
			
		||||
	libmio_la-fmt.lo libmio_la-mio.lo libmio_la-nwif.lo \
 | 
			
		||||
	libmio_la-pro.lo libmio_la-sck.lo libmio_la-skad.lo \
 | 
			
		||||
	libmio_la-sys.lo libmio_la-sys-ass.lo libmio_la-sys-err.lo \
 | 
			
		||||
	libmio_la-sys-log.lo libmio_la-sys-mux.lo libmio_la-sys-tim.lo \
 | 
			
		||||
	libmio_la-tmr.lo libmio_la-utf8.lo libmio_la-utl.lo
 | 
			
		||||
am_libmio_la_OBJECTS = libmio_la-dns.lo libmio_la-dns-cli.lo \
 | 
			
		||||
	libmio_la-err.lo libmio_la-fmt.lo libmio_la-mio.lo \
 | 
			
		||||
	libmio_la-nwif.lo libmio_la-pro.lo libmio_la-sck.lo \
 | 
			
		||||
	libmio_la-skad.lo libmio_la-sys.lo libmio_la-sys-ass.lo \
 | 
			
		||||
	libmio_la-sys-err.lo libmio_la-sys-log.lo libmio_la-sys-mux.lo \
 | 
			
		||||
	libmio_la-sys-tim.lo libmio_la-tmr.lo libmio_la-utf8.lo \
 | 
			
		||||
	libmio_la-utl.lo
 | 
			
		||||
libmio_la_OBJECTS = $(am_libmio_la_OBJECTS)
 | 
			
		||||
AM_V_lt = $(am__v_lt_@AM_V@)
 | 
			
		||||
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
 | 
			
		||||
@ -167,11 +168,11 @@ am__v_at_1 =
 | 
			
		||||
DEFAULT_INCLUDES = 
 | 
			
		||||
depcomp = $(SHELL) $(top_srcdir)/ac/depcomp
 | 
			
		||||
am__maybe_remake_depfiles = depfiles
 | 
			
		||||
am__depfiles_remade = ./$(DEPDIR)/libmio_la-dns.Plo \
 | 
			
		||||
	./$(DEPDIR)/libmio_la-err.Plo ./$(DEPDIR)/libmio_la-fmt.Plo \
 | 
			
		||||
	./$(DEPDIR)/libmio_la-mio.Plo ./$(DEPDIR)/libmio_la-nwif.Plo \
 | 
			
		||||
	./$(DEPDIR)/libmio_la-pro.Plo ./$(DEPDIR)/libmio_la-sck.Plo \
 | 
			
		||||
	./$(DEPDIR)/libmio_la-skad.Plo \
 | 
			
		||||
am__depfiles_remade = ./$(DEPDIR)/libmio_la-dns-cli.Plo \
 | 
			
		||||
	./$(DEPDIR)/libmio_la-dns.Plo ./$(DEPDIR)/libmio_la-err.Plo \
 | 
			
		||||
	./$(DEPDIR)/libmio_la-fmt.Plo ./$(DEPDIR)/libmio_la-mio.Plo \
 | 
			
		||||
	./$(DEPDIR)/libmio_la-nwif.Plo ./$(DEPDIR)/libmio_la-pro.Plo \
 | 
			
		||||
	./$(DEPDIR)/libmio_la-sck.Plo ./$(DEPDIR)/libmio_la-skad.Plo \
 | 
			
		||||
	./$(DEPDIR)/libmio_la-sys-ass.Plo \
 | 
			
		||||
	./$(DEPDIR)/libmio_la-sys-err.Plo \
 | 
			
		||||
	./$(DEPDIR)/libmio_la-sys-log.Plo \
 | 
			
		||||
@ -411,6 +412,7 @@ include_HEADERS = \
 | 
			
		||||
lib_LTLIBRARIES = libmio.la
 | 
			
		||||
libmio_la_SOURCES = \
 | 
			
		||||
	dns.c \
 | 
			
		||||
	dns-cli.c \
 | 
			
		||||
	err.c \
 | 
			
		||||
	fmt.c \
 | 
			
		||||
	fmt-imp.h \
 | 
			
		||||
@ -528,6 +530,7 @@ mostlyclean-compile:
 | 
			
		||||
distclean-compile:
 | 
			
		||||
	-rm -f *.tab.c
 | 
			
		||||
 | 
			
		||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmio_la-dns-cli.Plo@am__quote@ # am--include-marker
 | 
			
		||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmio_la-dns.Plo@am__quote@ # am--include-marker
 | 
			
		||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmio_la-err.Plo@am__quote@ # am--include-marker
 | 
			
		||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmio_la-fmt.Plo@am__quote@ # am--include-marker
 | 
			
		||||
@ -583,6 +586,13 @@ libmio_la-dns.lo: dns.c
 | 
			
		||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 | 
			
		||||
@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmio_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libmio_la-dns.lo `test -f 'dns.c' || echo '$(srcdir)/'`dns.c
 | 
			
		||||
 | 
			
		||||
libmio_la-dns-cli.lo: dns-cli.c
 | 
			
		||||
@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmio_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libmio_la-dns-cli.lo -MD -MP -MF $(DEPDIR)/libmio_la-dns-cli.Tpo -c -o libmio_la-dns-cli.lo `test -f 'dns-cli.c' || echo '$(srcdir)/'`dns-cli.c
 | 
			
		||||
@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libmio_la-dns-cli.Tpo $(DEPDIR)/libmio_la-dns-cli.Plo
 | 
			
		||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='dns-cli.c' object='libmio_la-dns-cli.lo' libtool=yes @AMDEPBACKSLASH@
 | 
			
		||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 | 
			
		||||
@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmio_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libmio_la-dns-cli.lo `test -f 'dns-cli.c' || echo '$(srcdir)/'`dns-cli.c
 | 
			
		||||
 | 
			
		||||
libmio_la-err.lo: err.c
 | 
			
		||||
@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmio_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libmio_la-err.lo -MD -MP -MF $(DEPDIR)/libmio_la-err.Tpo -c -o libmio_la-err.lo `test -f 'err.c' || echo '$(srcdir)/'`err.c
 | 
			
		||||
@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libmio_la-err.Tpo $(DEPDIR)/libmio_la-err.Plo
 | 
			
		||||
@ -850,7 +860,8 @@ clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
 | 
			
		||||
	mostlyclean-am
 | 
			
		||||
 | 
			
		||||
distclean: distclean-am
 | 
			
		||||
		-rm -f ./$(DEPDIR)/libmio_la-dns.Plo
 | 
			
		||||
		-rm -f ./$(DEPDIR)/libmio_la-dns-cli.Plo
 | 
			
		||||
	-rm -f ./$(DEPDIR)/libmio_la-dns.Plo
 | 
			
		||||
	-rm -f ./$(DEPDIR)/libmio_la-err.Plo
 | 
			
		||||
	-rm -f ./$(DEPDIR)/libmio_la-fmt.Plo
 | 
			
		||||
	-rm -f ./$(DEPDIR)/libmio_la-mio.Plo
 | 
			
		||||
@ -913,7 +924,8 @@ install-ps-am:
 | 
			
		||||
installcheck-am:
 | 
			
		||||
 | 
			
		||||
maintainer-clean: maintainer-clean-am
 | 
			
		||||
		-rm -f ./$(DEPDIR)/libmio_la-dns.Plo
 | 
			
		||||
		-rm -f ./$(DEPDIR)/libmio_la-dns-cli.Plo
 | 
			
		||||
	-rm -f ./$(DEPDIR)/libmio_la-dns.Plo
 | 
			
		||||
	-rm -f ./$(DEPDIR)/libmio_la-err.Plo
 | 
			
		||||
	-rm -f ./$(DEPDIR)/libmio_la-fmt.Plo
 | 
			
		||||
	-rm -f ./$(DEPDIR)/libmio_la-mio.Plo
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										573
									
								
								mio/lib/dns-cli.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										573
									
								
								mio/lib/dns-cli.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,573 @@
 | 
			
		||||
/*
 | 
			
		||||
 * $Id$
 | 
			
		||||
 *
 | 
			
		||||
    Copyright (c) 2016-2020 Chung, Hyung-Hwan. All rights reserved.
 | 
			
		||||
 | 
			
		||||
    Redistribution and use in source and binary forms, with or without
 | 
			
		||||
    modification, are permitted provided that the following conditions
 | 
			
		||||
    are met:
 | 
			
		||||
    1. Redistributions of source code must retain the above copyright
 | 
			
		||||
       notice, this list of conditions and the following disclaimer.
 | 
			
		||||
    2. Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
       notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
       documentation and/or other materials provided with the distribution.
 | 
			
		||||
 | 
			
		||||
    THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 | 
			
		||||
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WAfRRANTIES
 | 
			
		||||
    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 | 
			
		||||
    IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 | 
			
		||||
    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 | 
			
		||||
    NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
			
		||||
    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
			
		||||
    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
			
		||||
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 | 
			
		||||
    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <mio-dns.h>
 | 
			
		||||
#include <mio-sck.h>
 | 
			
		||||
#include "mio-prv.h"
 | 
			
		||||
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
 | 
			
		||||
struct mio_svc_dns_t
 | 
			
		||||
{
 | 
			
		||||
	MIO_SVC_HEADERS;
 | 
			
		||||
	/*MIO_DNS_SVC_HEADERS;*/
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct mio_svc_dnc_t
 | 
			
		||||
{
 | 
			
		||||
	MIO_SVC_HEADERS;
 | 
			
		||||
	/*MIO_DNS_SVC_HEADERS;*/
 | 
			
		||||
 | 
			
		||||
	mio_dev_sck_t* udp_sck;
 | 
			
		||||
	mio_dev_sck_t* tcp_sck;
 | 
			
		||||
	mio_skad_t serv_addr;
 | 
			
		||||
 | 
			
		||||
	mio_ntime_t send_tmout; 
 | 
			
		||||
	mio_ntime_t reply_tmout; /* default reply timeout */
 | 
			
		||||
	mio_oow_t reply_tmout_max_tries;
 | 
			
		||||
 | 
			
		||||
	mio_oow_t seq;
 | 
			
		||||
	mio_dns_msg_t* pending_req;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct dnc_sck_xtn_t
 | 
			
		||||
{
 | 
			
		||||
	mio_svc_dnc_t* dnc;
 | 
			
		||||
};
 | 
			
		||||
typedef struct dnc_sck_xtn_t dnc_sck_xtn_t;
 | 
			
		||||
 | 
			
		||||
/* ----------------------------------------------------------------------- */
 | 
			
		||||
 | 
			
		||||
struct dnc_dns_msg_xtn_t
 | 
			
		||||
{
 | 
			
		||||
	mio_dev_t*     dev;
 | 
			
		||||
	mio_tmridx_t   rtmridx;
 | 
			
		||||
	mio_dns_msg_t* prev;
 | 
			
		||||
	mio_dns_msg_t* next;
 | 
			
		||||
	mio_skad_t     servaddr;
 | 
			
		||||
	mio_svc_dnc_on_reply_t on_reply;
 | 
			
		||||
	mio_ntime_t    wtmout;
 | 
			
		||||
	mio_ntime_t    rtmout;
 | 
			
		||||
	int            rmaxtries; /* maximum number of tries to receive a reply */
 | 
			
		||||
	int            rtries; /* number of tries made so far */
 | 
			
		||||
};
 | 
			
		||||
typedef struct dnc_dns_msg_xtn_t dnc_dns_msg_xtn_t;
 | 
			
		||||
 | 
			
		||||
#if defined(MIO_HAVE_INLINE)
 | 
			
		||||
	static MIO_INLINE dnc_dns_msg_xtn_t* dnc_dns_msg_getxtn(mio_dns_msg_t* msg) { return (dnc_dns_msg_xtn_t*)((mio_uint8_t*)mio_dns_msg_to_pkt(msg) + msg->pktalilen); }
 | 
			
		||||
#else
 | 
			
		||||
#	define dnc_dns_msg_getxtn(msg) ((dnc_dns_msg_xtn_t*)((mio_uint8_t*)mio_dns_msg_to_pkt(msg) + msg->pktalilen))
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static mio_dns_msg_t* build_dns_msg (mio_svc_dnc_t* dnc, mio_dns_bhdr_t* bdns, mio_dns_bqr_t* qr, mio_oow_t qr_count, mio_dns_brr_t* rr, mio_oow_t rr_count, mio_dns_bedns_t* edns, mio_oow_t xtnsize)
 | 
			
		||||
{
 | 
			
		||||
	mio_dns_msg_t* msg;
 | 
			
		||||
	dnc_dns_msg_xtn_t* msgxtn;
 | 
			
		||||
 | 
			
		||||
	msg = mio_dns_make_msg(dnc->mio, bdns, qr, qr_count, rr, rr_count, edns, MIO_SIZEOF(*msgxtn) + xtnsize);
 | 
			
		||||
	if (msg)
 | 
			
		||||
	{
 | 
			
		||||
		
 | 
			
		||||
		if (bdns->id < 0)
 | 
			
		||||
		{
 | 
			
		||||
			mio_dns_pkt_t* pkt = mio_dns_msg_to_pkt(msg);
 | 
			
		||||
			pkt->id = mio_hton16(dnc->seq);
 | 
			
		||||
			dnc->seq++;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		msgxtn = dnc_dns_msg_getxtn(msg);
 | 
			
		||||
		msgxtn->dev = (mio_dev_t*)dnc->udp_sck;
 | 
			
		||||
		msgxtn->rtmridx = MIO_TMRIDX_INVALID;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return msg;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MIO_INLINE void chain_pending_dns_reqmsg (mio_svc_dnc_t* dnc, mio_dns_msg_t* msg)
 | 
			
		||||
{
 | 
			
		||||
	if (dnc->pending_req)
 | 
			
		||||
	{
 | 
			
		||||
		dnc_dns_msg_getxtn(dnc->pending_req)->prev = msg;
 | 
			
		||||
		dnc_dns_msg_getxtn(msg)->next = dnc->pending_req;
 | 
			
		||||
	}
 | 
			
		||||
	dnc->pending_req = msg;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MIO_INLINE void unchain_pending_dns_reqmsg (mio_svc_dnc_t* dnc, mio_dns_msg_t* msg)
 | 
			
		||||
{
 | 
			
		||||
	dnc_dns_msg_xtn_t* msgxtn = dnc_dns_msg_getxtn(msg);
 | 
			
		||||
	if (msgxtn->next) dnc_dns_msg_getxtn(msgxtn->next)->prev = msgxtn->prev;
 | 
			
		||||
	if (msgxtn->prev) dnc_dns_msg_getxtn(msgxtn->prev)->next = msgxtn->next;
 | 
			
		||||
	else dnc->pending_req = msgxtn->next;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void release_dns_msg (mio_svc_dnc_t* dnc, mio_dns_msg_t* msg)
 | 
			
		||||
{
 | 
			
		||||
	mio_t* mio = dnc->mio;
 | 
			
		||||
	dnc_dns_msg_xtn_t* msgxtn = dnc_dns_msg_getxtn(msg);
 | 
			
		||||
 | 
			
		||||
MIO_DEBUG1 (mio, "releasing dns msg %d\n", (int)mio_ntoh16(mio_dns_msg_to_pkt(msg)->id));
 | 
			
		||||
 | 
			
		||||
	if (msg == dnc->pending_req || msgxtn->next || msgxtn->prev)
 | 
			
		||||
	{
 | 
			
		||||
		/* it's chained in the pending request. unchain it */
 | 
			
		||||
		unchain_pending_dns_reqmsg (dnc, msg);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
/* TODO:  add it to the free msg list instead of just freeing it. */
 | 
			
		||||
	if (msgxtn->rtmridx != MIO_TMRIDX_INVALID)
 | 
			
		||||
	{
 | 
			
		||||
		mio_deltmrjob (mio, msgxtn->rtmridx);
 | 
			
		||||
		MIO_ASSERT (mio, msgxtn->rtmridx == MIO_TMRIDX_INVALID);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mio_dns_free_msg (dnc->mio, msg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int on_udp_read (mio_dev_sck_t* dev, const void* data, mio_iolen_t dlen, const mio_skad_t* srcaddr)
 | 
			
		||||
{
 | 
			
		||||
	mio_t* mio = dev->mio;
 | 
			
		||||
	mio_svc_dnc_t* dnc = ((dnc_sck_xtn_t*)mio_dev_sck_getxtn(dev))->dnc;
 | 
			
		||||
	mio_dns_pkt_t* pkt;
 | 
			
		||||
	mio_dns_msg_t* reqmsg;
 | 
			
		||||
	mio_uint16_t id;
 | 
			
		||||
 | 
			
		||||
	if (MIO_UNLIKELY(dlen < MIO_SIZEOF(*pkt))) 
 | 
			
		||||
	{
 | 
			
		||||
		MIO_DEBUG0 (mio, "dns packet too small from ....\n"); /* TODO: add source packet */
 | 
			
		||||
		return 0; /* drop */
 | 
			
		||||
	}
 | 
			
		||||
	pkt = (mio_dns_pkt_t*)data;
 | 
			
		||||
	if (!pkt->qr) 
 | 
			
		||||
	{
 | 
			
		||||
		MIO_DEBUG0 (mio, "dropping dns request received ...\n"); /* TODO: add source info */
 | 
			
		||||
		return 0; /* drop request */
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	id = mio_ntoh16(pkt->id);
 | 
			
		||||
 | 
			
		||||
	/* if id doesn't match one of the pending requests sent,  drop it */
 | 
			
		||||
 | 
			
		||||
/* TODO: improve performance of dns response matching*/
 | 
			
		||||
	reqmsg = dnc->pending_req;
 | 
			
		||||
	while (reqmsg)
 | 
			
		||||
	{
 | 
			
		||||
		mio_dns_pkt_t* reqpkt = mio_dns_msg_to_pkt(reqmsg);
 | 
			
		||||
		dnc_dns_msg_xtn_t* reqmsgxtn = dnc_dns_msg_getxtn(reqmsg);
 | 
			
		||||
 | 
			
		||||
		if (dev == (mio_dev_sck_t*)reqmsgxtn->dev && pkt->id == reqpkt->id && mio_equal_skads(&reqmsgxtn->servaddr, srcaddr, 0))
 | 
			
		||||
		{
 | 
			
		||||
			if (pkt->tc) /* truncated */
 | 
			
		||||
			{
 | 
			
		||||
				/* TODO: add an option for this behavior */
 | 
			
		||||
				/* TODO: switch to tc ... send the same request over tcp... */
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
MIO_DEBUG1 (mio, "received dns response...id %d\n", id);
 | 
			
		||||
			if (MIO_LIKELY(reqmsgxtn->on_reply))
 | 
			
		||||
				reqmsgxtn->on_reply (dnc, reqmsg, MIO_ENOERR, data, dlen);
 | 
			
		||||
 | 
			
		||||
			release_dns_msg (dnc, reqmsg);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
		reqmsg = reqmsgxtn->next;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* the response id didn't match the ID of pending requests - need to wait longer? */
 | 
			
		||||
MIO_DEBUG1 (mio, "unknown dns response... %d\n", pkt->id); /* TODO: add source info */
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void on_udp_reply_timeout (mio_t* mio, const mio_ntime_t* now, mio_tmrjob_t* job)
 | 
			
		||||
{
 | 
			
		||||
	mio_dns_msg_t* reqmsg = (mio_dns_msg_t*)job->ctx;
 | 
			
		||||
	dnc_dns_msg_xtn_t* msgxtn = dnc_dns_msg_getxtn(reqmsg);
 | 
			
		||||
	mio_dev_sck_t* dev = (mio_dev_sck_t*)msgxtn->dev;
 | 
			
		||||
	mio_svc_dnc_t* dnc = ((dnc_sck_xtn_t*)mio_dev_sck_getxtn(dev))->dnc;
 | 
			
		||||
 | 
			
		||||
	MIO_ASSERT (mio, msgxtn->rtmridx == MIO_TMRIDX_INVALID);
 | 
			
		||||
 | 
			
		||||
MIO_DEBUG0 (mio, "*** TIMEOUT ==> unable to receive dns response in time...\n");
 | 
			
		||||
	if (msgxtn->rtries < msgxtn->rmaxtries)
 | 
			
		||||
	{
 | 
			
		||||
		mio_ntime_t* tmout;
 | 
			
		||||
 | 
			
		||||
		tmout = MIO_IS_POS_NTIME(&msgxtn->wtmout)? &msgxtn->wtmout: MIO_NULL;
 | 
			
		||||
		if (mio_dev_sck_timedwrite(dnc->udp_sck, mio_dns_msg_to_pkt(reqmsg), reqmsg->pktlen, tmout, reqmsg, &msgxtn->servaddr) <= -1)
 | 
			
		||||
		{
 | 
			
		||||
			if (MIO_LIKELY(msgxtn->on_reply))
 | 
			
		||||
				msgxtn->on_reply (dnc, reqmsg, MIO_ETMOUT, MIO_NULL, 0);
 | 
			
		||||
 | 
			
		||||
			release_dns_msg (dnc, reqmsg);
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
printf (">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> RESENT REQUEST >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> \n");
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		if (MIO_LIKELY(msgxtn->on_reply))
 | 
			
		||||
			msgxtn->on_reply (dnc, reqmsg, MIO_ETMOUT, MIO_NULL, 0);
 | 
			
		||||
		release_dns_msg (dnc, reqmsg);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int on_udp_write (mio_dev_sck_t* dev, mio_iolen_t wrlen, void* wrctx, const mio_skad_t* dstaddr)
 | 
			
		||||
{
 | 
			
		||||
	mio_t* mio = dev->mio;
 | 
			
		||||
	mio_dns_msg_t* msg = (mio_dns_msg_t*)wrctx;
 | 
			
		||||
	dnc_dns_msg_xtn_t* msgxtn = dnc_dns_msg_getxtn(msg);
 | 
			
		||||
	mio_svc_dnc_t* dnc = ((dnc_sck_xtn_t*)mio_dev_sck_getxtn(dev))->dnc;
 | 
			
		||||
 | 
			
		||||
MIO_DEBUG1 (mio, "sent dns message %d\n", (int)mio_ntoh16(mio_dns_msg_to_pkt(msg)->id));
 | 
			
		||||
 | 
			
		||||
	MIO_ASSERT (mio, dev == (mio_dev_sck_t*)msgxtn->dev);
 | 
			
		||||
 | 
			
		||||
	if (wrlen <= -1)
 | 
			
		||||
	{
 | 
			
		||||
		/* write has timed out or an error has occurred */
 | 
			
		||||
		if (MIO_LIKELY(msgxtn->on_reply))
 | 
			
		||||
			msgxtn->on_reply (dnc, msg, mio_geterrnum(mio), MIO_NULL, 0);
 | 
			
		||||
		release_dns_msg (dnc, msg);
 | 
			
		||||
	}
 | 
			
		||||
	else if (mio_dns_msg_to_pkt(msg)->qr == 0 && msgxtn->rmaxtries > 0)
 | 
			
		||||
	{
 | 
			
		||||
		/* question. schedule to wait for response */
 | 
			
		||||
		mio_tmrjob_t tmrjob;
 | 
			
		||||
 | 
			
		||||
		MIO_MEMSET (&tmrjob, 0, MIO_SIZEOF(tmrjob));
 | 
			
		||||
		tmrjob.ctx = msg;
 | 
			
		||||
		mio_gettime (mio, &tmrjob.when);
 | 
			
		||||
		MIO_ADD_NTIME (&tmrjob.when, &tmrjob.when, &msgxtn->rtmout);
 | 
			
		||||
		tmrjob.handler = on_udp_reply_timeout;
 | 
			
		||||
		tmrjob.idxptr = &msgxtn->rtmridx;
 | 
			
		||||
		msgxtn->rtmridx = mio_instmrjob(mio, &tmrjob);
 | 
			
		||||
		if (msgxtn->rtmridx == MIO_TMRIDX_INVALID)
 | 
			
		||||
		{
 | 
			
		||||
			/* call the callback to indicate this operation failure in the middle of transaction */
 | 
			
		||||
			if (MIO_LIKELY(msgxtn->on_reply))
 | 
			
		||||
				msgxtn->on_reply (dnc, msg, mio_geterrnum(mio), MIO_NULL, 0);
 | 
			
		||||
			release_dns_msg (dnc, msg);
 | 
			
		||||
 | 
			
		||||
			MIO_DEBUG0 (mio, "unable to schedule timeout...\n");
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			if (msgxtn->rtries == 0)
 | 
			
		||||
			{
 | 
			
		||||
				/* this is the first wait */
 | 
			
		||||
 | 
			
		||||
				/* TODO: improve performance. hashing by id? */
 | 
			
		||||
				/* chain it to the peing request list */
 | 
			
		||||
				chain_pending_dns_reqmsg (dnc, msg);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			msgxtn->rtries++;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		/* sent an answer - we don't need this any more */
 | 
			
		||||
		/* we don't call the on_reply callback stored in msg->ctx as this is not a reply context */
 | 
			
		||||
		release_dns_msg (dnc, msg);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void on_udp_connect (mio_dev_sck_t* dev)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void on_udp_disconnect (mio_dev_sck_t* dev)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
mio_svc_dnc_t* mio_svc_dnc_start (mio_t* mio, const mio_skad_t* serv_addr, const mio_skad_t* bind_addr, const mio_ntime_t* send_tmout, const mio_ntime_t* reply_tmout, mio_oow_t reply_tmout_max_tries)
 | 
			
		||||
{
 | 
			
		||||
	mio_svc_dnc_t* dnc = MIO_NULL;
 | 
			
		||||
	mio_dev_sck_make_t mkinfo;
 | 
			
		||||
	dnc_sck_xtn_t* xtn;
 | 
			
		||||
 | 
			
		||||
	dnc = (mio_svc_dnc_t*)mio_callocmem(mio, MIO_SIZEOF(*dnc));
 | 
			
		||||
	if (!dnc) goto oops;
 | 
			
		||||
 | 
			
		||||
	dnc->mio = mio;
 | 
			
		||||
	dnc->stop = mio_svc_dnc_stop;
 | 
			
		||||
	dnc->serv_addr = *serv_addr;
 | 
			
		||||
	dnc->send_tmout = *send_tmout;
 | 
			
		||||
	dnc->reply_tmout = *reply_tmout;
 | 
			
		||||
	dnc->reply_tmout_max_tries = reply_tmout_max_tries;
 | 
			
		||||
 | 
			
		||||
	MIO_MEMSET (&mkinfo, 0, MIO_SIZEOF(mkinfo));
 | 
			
		||||
	switch (mio_skad_family(serv_addr))
 | 
			
		||||
	{
 | 
			
		||||
		case MIO_AF_INET:
 | 
			
		||||
			mkinfo.type = MIO_DEV_SCK_UDP4;
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case MIO_AF_INET6:
 | 
			
		||||
			mkinfo.type = MIO_DEV_SCK_UDP6;
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		default:
 | 
			
		||||
			mio_seterrnum (mio, MIO_EINVAL);
 | 
			
		||||
			goto oops;
 | 
			
		||||
	}
 | 
			
		||||
	mkinfo.on_write = on_udp_write;
 | 
			
		||||
	mkinfo.on_read = on_udp_read;
 | 
			
		||||
	mkinfo.on_connect = on_udp_connect;
 | 
			
		||||
	mkinfo.on_disconnect = on_udp_disconnect;
 | 
			
		||||
	dnc->udp_sck = mio_dev_sck_make(mio, MIO_SIZEOF(*xtn), &mkinfo);
 | 
			
		||||
	if (!dnc->udp_sck) goto oops;
 | 
			
		||||
 | 
			
		||||
	xtn = (dnc_sck_xtn_t*)mio_dev_sck_getxtn(dnc->udp_sck);
 | 
			
		||||
	xtn->dnc = dnc;
 | 
			
		||||
 | 
			
		||||
	if (bind_addr) /* TODO: get mio_dev_sck_bind_t? instead of bind_addr? */
 | 
			
		||||
	{
 | 
			
		||||
		mio_dev_sck_bind_t bi;
 | 
			
		||||
		MIO_MEMSET (&bi, 0, MIO_SIZEOF(bi));
 | 
			
		||||
		bi.localaddr = *bind_addr;
 | 
			
		||||
		if (mio_dev_sck_bind(dnc->udp_sck, &bi) <= -1) goto oops;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	MIO_SVC_REGISTER (mio, (mio_svc_t*)dnc);
 | 
			
		||||
	return dnc;
 | 
			
		||||
 | 
			
		||||
oops:
 | 
			
		||||
	if (dnc)
 | 
			
		||||
	{
 | 
			
		||||
		if (dnc->udp_sck) mio_dev_sck_kill (dnc->udp_sck);
 | 
			
		||||
		mio_freemem (mio, dnc);
 | 
			
		||||
	}
 | 
			
		||||
	return MIO_NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void mio_svc_dnc_stop (mio_svc_dnc_t* dnc)
 | 
			
		||||
{
 | 
			
		||||
	mio_t* mio = dnc->mio;
 | 
			
		||||
	if (dnc->udp_sck) mio_dev_sck_kill (dnc->udp_sck);
 | 
			
		||||
	MIO_SVC_UNREGISTER (mio, dnc);
 | 
			
		||||
	while (dnc->pending_req) release_dns_msg (dnc, dnc->pending_req);
 | 
			
		||||
	mio_freemem (mio, dnc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
mio_dns_msg_t* mio_svc_dnc_sendmsg (mio_svc_dnc_t* dnc, mio_dns_bhdr_t* bdns, mio_dns_bqr_t* qr, mio_oow_t qr_count, mio_dns_brr_t* rr, mio_oow_t rr_count, mio_dns_bedns_t* edns, mio_svc_dnc_on_reply_t on_reply, mio_oow_t xtnsize)
 | 
			
		||||
{
 | 
			
		||||
	/* send a request or a response */
 | 
			
		||||
	mio_dns_msg_t* msg;
 | 
			
		||||
	dnc_dns_msg_xtn_t* msgxtn;
 | 
			
		||||
	mio_ntime_t* tmout;
 | 
			
		||||
 | 
			
		||||
	msg = build_dns_msg(dnc, bdns, qr, qr_count, rr, rr_count, edns, MIO_SIZEOF(*msgxtn) + xtnsize);
 | 
			
		||||
	if (!msg) return MIO_NULL;
 | 
			
		||||
 | 
			
		||||
	msgxtn = dnc_dns_msg_getxtn(msg);
 | 
			
		||||
	msgxtn->on_reply = on_reply;
 | 
			
		||||
	msgxtn->wtmout = dnc->send_tmout;
 | 
			
		||||
	msgxtn->rtmout = dnc->reply_tmout;
 | 
			
		||||
	msgxtn->rmaxtries = dnc->reply_tmout_max_tries; 
 | 
			
		||||
	msgxtn->rtries = 0;
 | 
			
		||||
	msgxtn->servaddr = dnc->serv_addr;
 | 
			
		||||
 | 
			
		||||
/* TODO: optionally, override dnc->serv_addr and use the target address passed as a parameter */
 | 
			
		||||
	tmout = MIO_IS_POS_NTIME(&msgxtn->wtmout)? &msgxtn->wtmout: MIO_NULL;
 | 
			
		||||
	if (mio_dev_sck_timedwrite(dnc->udp_sck, mio_dns_msg_to_pkt(msg), msg->pktlen, tmout, msg, &msgxtn->servaddr) <= -1)
 | 
			
		||||
	{
 | 
			
		||||
		release_dns_msg (dnc, msg);
 | 
			
		||||
		return MIO_NULL;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	return msg;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
mio_dns_msg_t* mio_svc_dnc_sendreq (mio_svc_dnc_t* dnc, mio_dns_bhdr_t* bdns, mio_dns_bqr_t* qr, mio_dns_bedns_t* edns, mio_svc_dnc_on_reply_t on_reply, mio_oow_t xtnsize)
 | 
			
		||||
{
 | 
			
		||||
	/* send a request without resource records */
 | 
			
		||||
	if (bdns->rcode != MIO_DNS_RCODE_NOERROR)
 | 
			
		||||
	{
 | 
			
		||||
		mio_seterrnum (dnc->mio, MIO_EINVAL);
 | 
			
		||||
		return MIO_NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return mio_svc_dnc_sendmsg(dnc, bdns, qr, 1, MIO_NULL, 0, edns, on_reply, xtnsize);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* ----------------------------------------------------------------------- */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct dnc_dns_msg_resolve_xtn_t
 | 
			
		||||
{
 | 
			
		||||
	mio_dns_rrt_t qtype;
 | 
			
		||||
	int flags;
 | 
			
		||||
	mio_svc_dnc_on_resolve_t on_resolve;
 | 
			
		||||
};
 | 
			
		||||
typedef struct dnc_dns_msg_resolve_xtn_t dnc_dns_msg_resolve_xtn_t;
 | 
			
		||||
 | 
			
		||||
#if defined(MIO_HAVE_INLINE)
 | 
			
		||||
	static MIO_INLINE dnc_dns_msg_resolve_xtn_t* dnc_dns_msg_resolve_getxtn(mio_dns_msg_t* msg) { return ((dnc_dns_msg_resolve_xtn_t*)((mio_uint8_t*)dnc_dns_msg_getxtn(msg) + MIO_SIZEOF(dnc_dns_msg_xtn_t))); }
 | 
			
		||||
#else
 | 
			
		||||
#	define dnc_dns_msg_resolve_getxtn(msg) ((dnc_dns_msg_resolve_xtn_t*)((mio_uint8_t*)dnc_dns_msg_getxtn(msg) + MIO_SIZEOF(dnc_dns_msg_xtn_t)))
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static void on_dnc_resolve (mio_svc_dnc_t* dnc, mio_dns_msg_t* reqmsg, mio_errnum_t status, const void* data, mio_oow_t dlen)
 | 
			
		||||
{
 | 
			
		||||
	mio_t* mio = mio_svc_dnc_getmio(dnc);
 | 
			
		||||
	mio_dns_pkt_info_t* pi = MIO_NULL;
 | 
			
		||||
	dnc_dns_msg_resolve_xtn_t* reqmsgxtn = dnc_dns_msg_resolve_getxtn(reqmsg);
 | 
			
		||||
 | 
			
		||||
	if (!(reqmsgxtn->flags & MIO_SVC_DNC_RESOLVE_FLAG_BRIEF))
 | 
			
		||||
	{
 | 
			
		||||
		/* the full reply packet is requested. no transformation is required */
 | 
			
		||||
		if (reqmsgxtn->on_resolve) reqmsgxtn->on_resolve(dnc, reqmsg, status, data, dlen);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (data)
 | 
			
		||||
	{
 | 
			
		||||
		mio_uint32_t i;
 | 
			
		||||
 | 
			
		||||
		MIO_ASSERT (mio, status == MIO_ENOERR);
 | 
			
		||||
 | 
			
		||||
		pi = mio_dns_make_packet_info(mio, data, dlen);
 | 
			
		||||
		if (!pi)
 | 
			
		||||
		{
 | 
			
		||||
			status = mio_geterrnum(mio);
 | 
			
		||||
			goto no_valid_reply;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (pi->hdr.rcode != MIO_DNS_RCODE_NOERROR) 
 | 
			
		||||
		{
 | 
			
		||||
			status = MIO_EINVAL;
 | 
			
		||||
			goto no_valid_reply;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (pi->ancount < 0) goto no_valid_reply;
 | 
			
		||||
 | 
			
		||||
		/* in the brief mode, we inspect the answer section only */
 | 
			
		||||
		if (reqmsgxtn->qtype == MIO_DNS_RRT_Q_ANY)
 | 
			
		||||
		{
 | 
			
		||||
			/* return A or AAAA for ANY in the brief mode */
 | 
			
		||||
			for (i = 0; i < pi->ancount; i++)
 | 
			
		||||
			{
 | 
			
		||||
				if (pi->rr.an[i].rrtype == MIO_DNS_RRT_A || pi->rr.an[i].rrtype == MIO_DNS_RRT_AAAA)
 | 
			
		||||
				{
 | 
			
		||||
				match_found:
 | 
			
		||||
					if (reqmsgxtn->on_resolve) reqmsgxtn->on_resolve (dnc, reqmsg, status, &pi->rr.an[i], MIO_SIZEOF(pi->rr.an[i]));
 | 
			
		||||
					goto done;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for (i = 0; i < pi->ancount; i++)
 | 
			
		||||
		{
 | 
			
		||||
			/* it is a bit time taking to retreive the query type from the packet
 | 
			
		||||
			 * bundled in reqmsg as it requires parsing of the packet. let me use
 | 
			
		||||
			 * the query type i stored in the extension space. */
 | 
			
		||||
			switch (reqmsgxtn->qtype)
 | 
			
		||||
			{
 | 
			
		||||
				case MIO_DNS_RRT_Q_ANY: 
 | 
			
		||||
				case MIO_DNS_RRT_Q_AFXR: /* AFXR doesn't make sense in the brief mode. just treat it like ANY */
 | 
			
		||||
					/* no A or AAAA found. so give the first entry in the answer */
 | 
			
		||||
					goto match_found;
 | 
			
		||||
 | 
			
		||||
				case MIO_DNS_RRT_Q_MAILA:
 | 
			
		||||
					/* if you want to get the full RRs, don't use the brief mode. */
 | 
			
		||||
					if (pi->rr.an[i].rrtype == MIO_DNS_RRT_MD || pi->rr.an[i].rrtype == MIO_DNS_RRT_MF) goto match_found;
 | 
			
		||||
					break;
 | 
			
		||||
 | 
			
		||||
				case MIO_DNS_RRT_Q_MAILB:
 | 
			
		||||
					/* if you want to get the full RRs, don't use the brief mode. */
 | 
			
		||||
					if (pi->rr.an[i].rrtype == MIO_DNS_RRT_MB || pi->rr.an[i].rrtype == MIO_DNS_RRT_MG ||
 | 
			
		||||
					    pi->rr.an[i].rrtype == MIO_DNS_RRT_MR || pi->rr.an[i].rrtype == MIO_DNS_RRT_MINFO) goto match_found;
 | 
			
		||||
					break;
 | 
			
		||||
 | 
			
		||||
				default:
 | 
			
		||||
					if (pi->rr.an[i].rrtype == reqmsgxtn->qtype) goto match_found;
 | 
			
		||||
					break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		goto no_valid_reply;
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
	no_valid_reply:
 | 
			
		||||
		if (reqmsgxtn->on_resolve) reqmsgxtn->on_resolve (dnc, reqmsg, status, MIO_NULL, 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
done:
 | 
			
		||||
	if (pi) mio_dns_free_packet_info(mio_svc_dnc_getmio(dnc), pi);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
mio_dns_msg_t* mio_svc_dnc_resolve (mio_svc_dnc_t* dnc, const mio_bch_t* qname, mio_dns_rrt_t qtype, int flags, mio_svc_dnc_on_resolve_t on_resolve, mio_oow_t xtnsize)
 | 
			
		||||
{
 | 
			
		||||
	static mio_dns_bhdr_t qhdr =
 | 
			
		||||
	{
 | 
			
		||||
		-1, /* id */
 | 
			
		||||
		0,  /* qr */
 | 
			
		||||
		MIO_DNS_OPCODE_QUERY, /* opcode */
 | 
			
		||||
		0, /* aa */
 | 
			
		||||
		0, /* tc */
 | 
			
		||||
		1, /* rd */
 | 
			
		||||
		0, /* ra */
 | 
			
		||||
		0, /* ad */
 | 
			
		||||
		0, /* cd */
 | 
			
		||||
		MIO_DNS_RCODE_NOERROR /* rcode */
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	static mio_dns_bedns_t qedns =
 | 
			
		||||
	{
 | 
			
		||||
		4096, /* uplen */
 | 
			
		||||
 | 
			
		||||
		0,    /* edns version */
 | 
			
		||||
		0,    /* dnssec ok */
 | 
			
		||||
 | 
			
		||||
		0,    /* number of edns options */
 | 
			
		||||
		MIO_NULL
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	mio_dns_bqr_t qr;
 | 
			
		||||
	mio_dns_msg_t* reqmsg;
 | 
			
		||||
	dnc_dns_msg_resolve_xtn_t* reqmsgxtn;
 | 
			
		||||
 | 
			
		||||
	qr.qname = (mio_bch_t*)qname;
 | 
			
		||||
	qr.qtype = qtype;
 | 
			
		||||
	qr.qclass = MIO_DNS_RRC_IN;
 | 
			
		||||
 | 
			
		||||
	reqmsg = mio_svc_dnc_sendmsg(dnc, &qhdr, &qr, 1, MIO_NULL, 0, &qedns, on_dnc_resolve, MIO_SIZEOF(*reqmsgxtn) + xtnsize);
 | 
			
		||||
	if (reqmsg)
 | 
			
		||||
	{
 | 
			
		||||
		reqmsgxtn = dnc_dns_msg_resolve_getxtn(reqmsg);
 | 
			
		||||
		reqmsgxtn->on_resolve = on_resolve;
 | 
			
		||||
		reqmsgxtn->qtype = qtype;
 | 
			
		||||
		reqmsgxtn->flags = flags;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return reqmsg;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										549
									
								
								mio/lib/dns.c
									
									
									
									
									
								
							
							
						
						
									
										549
									
								
								mio/lib/dns.c
									
									
									
									
									
								
							@ -24,41 +24,9 @@
 | 
			
		||||
    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <mio-dns.h>
 | 
			
		||||
#include <mio-sck.h>
 | 
			
		||||
#include "mio-dns.h"
 | 
			
		||||
#include "mio-prv.h"
 | 
			
		||||
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
 | 
			
		||||
struct mio_svc_dns_t
 | 
			
		||||
{
 | 
			
		||||
	MIO_SVC_HEADERS;
 | 
			
		||||
	/*MIO_DNS_SVC_HEADERS;*/
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct mio_svc_dnc_t
 | 
			
		||||
{
 | 
			
		||||
	MIO_SVC_HEADERS;
 | 
			
		||||
	/*MIO_DNS_SVC_HEADERS;*/
 | 
			
		||||
 | 
			
		||||
	mio_dev_sck_t* udp_sck;
 | 
			
		||||
	mio_dev_sck_t* tcp_sck;
 | 
			
		||||
	mio_skad_t serv_addr;
 | 
			
		||||
 | 
			
		||||
	mio_ntime_t send_tmout; 
 | 
			
		||||
	mio_ntime_t reply_tmout; /* default reply timeout */
 | 
			
		||||
	mio_oow_t reply_tmout_max_tries;
 | 
			
		||||
 | 
			
		||||
	mio_oow_t seq;
 | 
			
		||||
	mio_dns_msg_t* pending_req;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct dnc_sck_xtn_t
 | 
			
		||||
{
 | 
			
		||||
	mio_svc_dnc_t* dnc;
 | 
			
		||||
};
 | 
			
		||||
typedef struct dnc_sck_xtn_t dnc_sck_xtn_t;
 | 
			
		||||
 | 
			
		||||
/* ----------------------------------------------------------------------- */
 | 
			
		||||
 | 
			
		||||
#define DN_AT_END(ptr) (ptr[0] == '\0' || (ptr[0] == '.' && ptr[1] == '\0'))
 | 
			
		||||
@ -126,521 +94,6 @@ static mio_oow_t dn_length (mio_uint8_t* ptr, mio_oow_t len)
 | 
			
		||||
	return curptr - ptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* ----------------------------------------------------------------------- */
 | 
			
		||||
 | 
			
		||||
struct dnc_dns_msg_xtn_t
 | 
			
		||||
{
 | 
			
		||||
	mio_dev_t*     dev;
 | 
			
		||||
	mio_tmridx_t   rtmridx;
 | 
			
		||||
	mio_dns_msg_t* prev;
 | 
			
		||||
	mio_dns_msg_t* next;
 | 
			
		||||
	mio_skad_t     servaddr;
 | 
			
		||||
	mio_svc_dnc_on_reply_t on_reply;
 | 
			
		||||
	mio_ntime_t    wtmout;
 | 
			
		||||
	mio_ntime_t    rtmout;
 | 
			
		||||
	int            rmaxtries; /* maximum number of tries to receive a reply */
 | 
			
		||||
	int            rtries; /* number of tries made so far */
 | 
			
		||||
};
 | 
			
		||||
typedef struct dnc_dns_msg_xtn_t dnc_dns_msg_xtn_t;
 | 
			
		||||
 | 
			
		||||
#if defined(MIO_HAVE_INLINE)
 | 
			
		||||
	static MIO_INLINE dnc_dns_msg_xtn_t* dnc_dns_msg_getxtn(mio_dns_msg_t* msg) { return (dnc_dns_msg_xtn_t*)((mio_uint8_t*)mio_dns_msg_to_pkt(msg) + msg->pktalilen); }
 | 
			
		||||
#else
 | 
			
		||||
#	define dnc_dns_msg_getxtn(msg) ((dnc_dns_msg_xtn_t*)((mio_uint8_t*)mio_dns_msg_to_pkt(msg) + msg->pktalilen))
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static mio_dns_msg_t* build_dns_msg (mio_svc_dnc_t* dnc, mio_dns_bhdr_t* bdns, mio_dns_bqr_t* qr, mio_oow_t qr_count, mio_dns_brr_t* rr, mio_oow_t rr_count, mio_dns_bedns_t* edns, mio_oow_t xtnsize)
 | 
			
		||||
{
 | 
			
		||||
	mio_dns_msg_t* msg;
 | 
			
		||||
	dnc_dns_msg_xtn_t* msgxtn;
 | 
			
		||||
 | 
			
		||||
	msg = mio_dns_make_msg(dnc->mio, bdns, qr, qr_count, rr, rr_count, edns, MIO_SIZEOF(*msgxtn) + xtnsize);
 | 
			
		||||
	if (msg)
 | 
			
		||||
	{
 | 
			
		||||
		
 | 
			
		||||
		if (bdns->id < 0)
 | 
			
		||||
		{
 | 
			
		||||
			mio_dns_pkt_t* pkt = mio_dns_msg_to_pkt(msg);
 | 
			
		||||
			pkt->id = mio_hton16(dnc->seq);
 | 
			
		||||
			dnc->seq++;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		msgxtn = dnc_dns_msg_getxtn(msg);
 | 
			
		||||
		msgxtn->dev = (mio_dev_t*)dnc->udp_sck;
 | 
			
		||||
		msgxtn->rtmridx = MIO_TMRIDX_INVALID;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return msg;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MIO_INLINE void chain_pending_dns_reqmsg (mio_svc_dnc_t* dnc, mio_dns_msg_t* msg)
 | 
			
		||||
{
 | 
			
		||||
	if (dnc->pending_req)
 | 
			
		||||
	{
 | 
			
		||||
		dnc_dns_msg_getxtn(dnc->pending_req)->prev = msg;
 | 
			
		||||
		dnc_dns_msg_getxtn(msg)->next = dnc->pending_req;
 | 
			
		||||
	}
 | 
			
		||||
	dnc->pending_req = msg;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MIO_INLINE void unchain_pending_dns_reqmsg (mio_svc_dnc_t* dnc, mio_dns_msg_t* msg)
 | 
			
		||||
{
 | 
			
		||||
	dnc_dns_msg_xtn_t* msgxtn = dnc_dns_msg_getxtn(msg);
 | 
			
		||||
	if (msgxtn->next) dnc_dns_msg_getxtn(msgxtn->next)->prev = msgxtn->prev;
 | 
			
		||||
	if (msgxtn->prev) dnc_dns_msg_getxtn(msgxtn->prev)->next = msgxtn->next;
 | 
			
		||||
	else dnc->pending_req = msgxtn->next;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void release_dns_msg (mio_svc_dnc_t* dnc, mio_dns_msg_t* msg)
 | 
			
		||||
{
 | 
			
		||||
	mio_t* mio = dnc->mio;
 | 
			
		||||
	dnc_dns_msg_xtn_t* msgxtn = dnc_dns_msg_getxtn(msg);
 | 
			
		||||
 | 
			
		||||
MIO_DEBUG1 (mio, "releasing dns msg %d\n", (int)mio_ntoh16(mio_dns_msg_to_pkt(msg)->id));
 | 
			
		||||
 | 
			
		||||
	if (msg == dnc->pending_req || msgxtn->next || msgxtn->prev)
 | 
			
		||||
	{
 | 
			
		||||
		/* it's chained in the pending request. unchain it */
 | 
			
		||||
		unchain_pending_dns_reqmsg (dnc, msg);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
/* TODO:  add it to the free msg list instead of just freeing it. */
 | 
			
		||||
	if (msgxtn->rtmridx != MIO_TMRIDX_INVALID)
 | 
			
		||||
	{
 | 
			
		||||
		mio_deltmrjob (mio, msgxtn->rtmridx);
 | 
			
		||||
		MIO_ASSERT (mio, msgxtn->rtmridx == MIO_TMRIDX_INVALID);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mio_dns_free_msg (dnc->mio, msg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int on_udp_read (mio_dev_sck_t* dev, const void* data, mio_iolen_t dlen, const mio_skad_t* srcaddr)
 | 
			
		||||
{
 | 
			
		||||
	mio_t* mio = dev->mio;
 | 
			
		||||
	mio_svc_dnc_t* dnc = ((dnc_sck_xtn_t*)mio_dev_sck_getxtn(dev))->dnc;
 | 
			
		||||
	mio_dns_pkt_t* pkt;
 | 
			
		||||
	mio_dns_msg_t* reqmsg;
 | 
			
		||||
	mio_uint16_t id;
 | 
			
		||||
 | 
			
		||||
	if (MIO_UNLIKELY(dlen < MIO_SIZEOF(*pkt))) 
 | 
			
		||||
	{
 | 
			
		||||
		MIO_DEBUG0 (mio, "dns packet too small from ....\n"); /* TODO: add source packet */
 | 
			
		||||
		return 0; /* drop */
 | 
			
		||||
	}
 | 
			
		||||
	pkt = (mio_dns_pkt_t*)data;
 | 
			
		||||
	if (!pkt->qr) 
 | 
			
		||||
	{
 | 
			
		||||
		MIO_DEBUG0 (mio, "dropping dns request received ...\n"); /* TODO: add source info */
 | 
			
		||||
		return 0; /* drop request */
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	id = mio_ntoh16(pkt->id);
 | 
			
		||||
 | 
			
		||||
	/* if id doesn't match one of the pending requests sent,  drop it */
 | 
			
		||||
 | 
			
		||||
/* TODO: improve performance of dns response matching*/
 | 
			
		||||
	reqmsg = dnc->pending_req;
 | 
			
		||||
	while (reqmsg)
 | 
			
		||||
	{
 | 
			
		||||
		mio_dns_pkt_t* reqpkt = mio_dns_msg_to_pkt(reqmsg);
 | 
			
		||||
		dnc_dns_msg_xtn_t* reqmsgxtn = dnc_dns_msg_getxtn(reqmsg);
 | 
			
		||||
 | 
			
		||||
		if (dev == (mio_dev_sck_t*)reqmsgxtn->dev && pkt->id == reqpkt->id && mio_equal_skads(&reqmsgxtn->servaddr, srcaddr, 0))
 | 
			
		||||
		{
 | 
			
		||||
			if (pkt->tc) /* truncated */
 | 
			
		||||
			{
 | 
			
		||||
				/* TODO: add an option for this behavior */
 | 
			
		||||
				/* TODO: switch to tc ... send the same request over tcp... */
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
MIO_DEBUG1 (mio, "received dns response...id %d\n", id);
 | 
			
		||||
			if (MIO_LIKELY(reqmsgxtn->on_reply))
 | 
			
		||||
				reqmsgxtn->on_reply (dnc, reqmsg, MIO_ENOERR, data, dlen);
 | 
			
		||||
 | 
			
		||||
			release_dns_msg (dnc, reqmsg);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
		reqmsg = reqmsgxtn->next;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* the response id didn't match the ID of pending requests - need to wait longer? */
 | 
			
		||||
MIO_DEBUG1 (mio, "unknown dns response... %d\n", pkt->id); /* TODO: add source info */
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void on_udp_reply_timeout (mio_t* mio, const mio_ntime_t* now, mio_tmrjob_t* job)
 | 
			
		||||
{
 | 
			
		||||
	mio_dns_msg_t* reqmsg = (mio_dns_msg_t*)job->ctx;
 | 
			
		||||
	dnc_dns_msg_xtn_t* msgxtn = dnc_dns_msg_getxtn(reqmsg);
 | 
			
		||||
	mio_dev_sck_t* dev = (mio_dev_sck_t*)msgxtn->dev;
 | 
			
		||||
	mio_svc_dnc_t* dnc = ((dnc_sck_xtn_t*)mio_dev_sck_getxtn(dev))->dnc;
 | 
			
		||||
 | 
			
		||||
	MIO_ASSERT (mio, msgxtn->rtmridx == MIO_TMRIDX_INVALID);
 | 
			
		||||
 | 
			
		||||
MIO_DEBUG0 (mio, "*** TIMEOUT ==> unable to receive dns response in time...\n");
 | 
			
		||||
	if (msgxtn->rtries < msgxtn->rmaxtries)
 | 
			
		||||
	{
 | 
			
		||||
		mio_ntime_t* tmout;
 | 
			
		||||
 | 
			
		||||
		tmout = MIO_IS_POS_NTIME(&msgxtn->wtmout)? &msgxtn->wtmout: MIO_NULL;
 | 
			
		||||
		if (mio_dev_sck_timedwrite(dnc->udp_sck, mio_dns_msg_to_pkt(reqmsg), reqmsg->pktlen, tmout, reqmsg, &msgxtn->servaddr) <= -1)
 | 
			
		||||
		{
 | 
			
		||||
			if (MIO_LIKELY(msgxtn->on_reply))
 | 
			
		||||
				msgxtn->on_reply (dnc, reqmsg, MIO_ETMOUT, MIO_NULL, 0);
 | 
			
		||||
 | 
			
		||||
			release_dns_msg (dnc, reqmsg);
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
printf (">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> RESENT REQUEST >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> \n");
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		if (MIO_LIKELY(msgxtn->on_reply))
 | 
			
		||||
			msgxtn->on_reply (dnc, reqmsg, MIO_ETMOUT, MIO_NULL, 0);
 | 
			
		||||
		release_dns_msg (dnc, reqmsg);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int on_udp_write (mio_dev_sck_t* dev, mio_iolen_t wrlen, void* wrctx, const mio_skad_t* dstaddr)
 | 
			
		||||
{
 | 
			
		||||
	mio_t* mio = dev->mio;
 | 
			
		||||
	mio_dns_msg_t* msg = (mio_dns_msg_t*)wrctx;
 | 
			
		||||
	dnc_dns_msg_xtn_t* msgxtn = dnc_dns_msg_getxtn(msg);
 | 
			
		||||
	mio_svc_dnc_t* dnc = ((dnc_sck_xtn_t*)mio_dev_sck_getxtn(dev))->dnc;
 | 
			
		||||
 | 
			
		||||
MIO_DEBUG1 (mio, "sent dns message %d\n", (int)mio_ntoh16(mio_dns_msg_to_pkt(msg)->id));
 | 
			
		||||
 | 
			
		||||
	MIO_ASSERT (mio, dev == (mio_dev_sck_t*)msgxtn->dev);
 | 
			
		||||
 | 
			
		||||
	if (wrlen <= -1)
 | 
			
		||||
	{
 | 
			
		||||
		/* write has timed out or an error has occurred */
 | 
			
		||||
		if (MIO_LIKELY(msgxtn->on_reply))
 | 
			
		||||
			msgxtn->on_reply (dnc, msg, mio_geterrnum(mio), MIO_NULL, 0);
 | 
			
		||||
		release_dns_msg (dnc, msg);
 | 
			
		||||
	}
 | 
			
		||||
	else if (mio_dns_msg_to_pkt(msg)->qr == 0 && msgxtn->rmaxtries > 0)
 | 
			
		||||
	{
 | 
			
		||||
		/* question. schedule to wait for response */
 | 
			
		||||
		mio_tmrjob_t tmrjob;
 | 
			
		||||
 | 
			
		||||
		MIO_MEMSET (&tmrjob, 0, MIO_SIZEOF(tmrjob));
 | 
			
		||||
		tmrjob.ctx = msg;
 | 
			
		||||
		mio_gettime (mio, &tmrjob.when);
 | 
			
		||||
		MIO_ADD_NTIME (&tmrjob.when, &tmrjob.when, &msgxtn->rtmout);
 | 
			
		||||
		tmrjob.handler = on_udp_reply_timeout;
 | 
			
		||||
		tmrjob.idxptr = &msgxtn->rtmridx;
 | 
			
		||||
		msgxtn->rtmridx = mio_instmrjob(mio, &tmrjob);
 | 
			
		||||
		if (msgxtn->rtmridx == MIO_TMRIDX_INVALID)
 | 
			
		||||
		{
 | 
			
		||||
			/* call the callback to indicate this operation failure in the middle of transaction */
 | 
			
		||||
			if (MIO_LIKELY(msgxtn->on_reply))
 | 
			
		||||
				msgxtn->on_reply (dnc, msg, mio_geterrnum(mio), MIO_NULL, 0);
 | 
			
		||||
			release_dns_msg (dnc, msg);
 | 
			
		||||
 | 
			
		||||
			MIO_DEBUG0 (mio, "unable to schedule timeout...\n");
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			if (msgxtn->rtries == 0)
 | 
			
		||||
			{
 | 
			
		||||
				/* this is the first wait */
 | 
			
		||||
 | 
			
		||||
				/* TODO: improve performance. hashing by id? */
 | 
			
		||||
				/* chain it to the peing request list */
 | 
			
		||||
				chain_pending_dns_reqmsg (dnc, msg);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			msgxtn->rtries++;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		/* sent an answer - we don't need this any more */
 | 
			
		||||
		/* we don't call the on_reply callback stored in msg->ctx as this is not a reply context */
 | 
			
		||||
		release_dns_msg (dnc, msg);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void on_udp_connect (mio_dev_sck_t* dev)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void on_udp_disconnect (mio_dev_sck_t* dev)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
mio_svc_dnc_t* mio_svc_dnc_start (mio_t* mio, const mio_skad_t* serv_addr, const mio_skad_t* bind_addr, const mio_ntime_t* send_tmout, const mio_ntime_t* reply_tmout, mio_oow_t reply_tmout_max_tries)
 | 
			
		||||
{
 | 
			
		||||
	mio_svc_dnc_t* dnc = MIO_NULL;
 | 
			
		||||
	mio_dev_sck_make_t mkinfo;
 | 
			
		||||
	dnc_sck_xtn_t* xtn;
 | 
			
		||||
 | 
			
		||||
	dnc = (mio_svc_dnc_t*)mio_callocmem(mio, MIO_SIZEOF(*dnc));
 | 
			
		||||
	if (!dnc) goto oops;
 | 
			
		||||
 | 
			
		||||
	dnc->mio = mio;
 | 
			
		||||
	dnc->stop = mio_svc_dnc_stop;
 | 
			
		||||
	dnc->serv_addr = *serv_addr;
 | 
			
		||||
	dnc->send_tmout = *send_tmout;
 | 
			
		||||
	dnc->reply_tmout = *reply_tmout;
 | 
			
		||||
	dnc->reply_tmout_max_tries = reply_tmout_max_tries;
 | 
			
		||||
 | 
			
		||||
	MIO_MEMSET (&mkinfo, 0, MIO_SIZEOF(mkinfo));
 | 
			
		||||
	switch (mio_skad_family(serv_addr))
 | 
			
		||||
	{
 | 
			
		||||
		case MIO_AF_INET:
 | 
			
		||||
			mkinfo.type = MIO_DEV_SCK_UDP4;
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case MIO_AF_INET6:
 | 
			
		||||
			mkinfo.type = MIO_DEV_SCK_UDP6;
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		default:
 | 
			
		||||
			mio_seterrnum (mio, MIO_EINVAL);
 | 
			
		||||
			goto oops;
 | 
			
		||||
	}
 | 
			
		||||
	mkinfo.on_write = on_udp_write;
 | 
			
		||||
	mkinfo.on_read = on_udp_read;
 | 
			
		||||
	mkinfo.on_connect = on_udp_connect;
 | 
			
		||||
	mkinfo.on_disconnect = on_udp_disconnect;
 | 
			
		||||
	dnc->udp_sck = mio_dev_sck_make(mio, MIO_SIZEOF(*xtn), &mkinfo);
 | 
			
		||||
	if (!dnc->udp_sck) goto oops;
 | 
			
		||||
 | 
			
		||||
	xtn = (dnc_sck_xtn_t*)mio_dev_sck_getxtn(dnc->udp_sck);
 | 
			
		||||
	xtn->dnc = dnc;
 | 
			
		||||
 | 
			
		||||
	if (bind_addr) /* TODO: get mio_dev_sck_bind_t? instead of bind_addr? */
 | 
			
		||||
	{
 | 
			
		||||
		mio_dev_sck_bind_t bi;
 | 
			
		||||
		MIO_MEMSET (&bi, 0, MIO_SIZEOF(bi));
 | 
			
		||||
		bi.localaddr = *bind_addr;
 | 
			
		||||
		if (mio_dev_sck_bind(dnc->udp_sck, &bi) <= -1) goto oops;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	MIO_SVC_REGISTER (mio, (mio_svc_t*)dnc);
 | 
			
		||||
	return dnc;
 | 
			
		||||
 | 
			
		||||
oops:
 | 
			
		||||
	if (dnc)
 | 
			
		||||
	{
 | 
			
		||||
		if (dnc->udp_sck) mio_dev_sck_kill (dnc->udp_sck);
 | 
			
		||||
		mio_freemem (mio, dnc);
 | 
			
		||||
	}
 | 
			
		||||
	return MIO_NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void mio_svc_dnc_stop (mio_svc_dnc_t* dnc)
 | 
			
		||||
{
 | 
			
		||||
	mio_t* mio = dnc->mio;
 | 
			
		||||
	if (dnc->udp_sck) mio_dev_sck_kill (dnc->udp_sck);
 | 
			
		||||
	MIO_SVC_UNREGISTER (mio, dnc);
 | 
			
		||||
	while (dnc->pending_req) release_dns_msg (dnc, dnc->pending_req);
 | 
			
		||||
	mio_freemem (mio, dnc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
mio_dns_msg_t* mio_svc_dnc_sendmsg (mio_svc_dnc_t* dnc, mio_dns_bhdr_t* bdns, mio_dns_bqr_t* qr, mio_oow_t qr_count, mio_dns_brr_t* rr, mio_oow_t rr_count, mio_dns_bedns_t* edns, mio_svc_dnc_on_reply_t on_reply, mio_oow_t xtnsize)
 | 
			
		||||
{
 | 
			
		||||
	/* send a request or a response */
 | 
			
		||||
	mio_dns_msg_t* msg;
 | 
			
		||||
	dnc_dns_msg_xtn_t* msgxtn;
 | 
			
		||||
	mio_ntime_t* tmout;
 | 
			
		||||
 | 
			
		||||
	msg = build_dns_msg(dnc, bdns, qr, qr_count, rr, rr_count, edns, MIO_SIZEOF(*msgxtn) + xtnsize);
 | 
			
		||||
	if (!msg) return MIO_NULL;
 | 
			
		||||
 | 
			
		||||
	msgxtn = dnc_dns_msg_getxtn(msg);
 | 
			
		||||
	msgxtn->on_reply = on_reply;
 | 
			
		||||
	msgxtn->wtmout = dnc->send_tmout;
 | 
			
		||||
	msgxtn->rtmout = dnc->reply_tmout;
 | 
			
		||||
	msgxtn->rmaxtries = dnc->reply_tmout_max_tries; 
 | 
			
		||||
	msgxtn->rtries = 0;
 | 
			
		||||
	msgxtn->servaddr = dnc->serv_addr;
 | 
			
		||||
 | 
			
		||||
/* TODO: optionally, override dnc->serv_addr and use the target address passed as a parameter */
 | 
			
		||||
	tmout = MIO_IS_POS_NTIME(&msgxtn->wtmout)? &msgxtn->wtmout: MIO_NULL;
 | 
			
		||||
	if (mio_dev_sck_timedwrite(dnc->udp_sck, mio_dns_msg_to_pkt(msg), msg->pktlen, tmout, msg, &msgxtn->servaddr) <= -1)
 | 
			
		||||
	{
 | 
			
		||||
		release_dns_msg (dnc, msg);
 | 
			
		||||
		return MIO_NULL;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	return msg;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
mio_dns_msg_t* mio_svc_dnc_sendreq (mio_svc_dnc_t* dnc, mio_dns_bhdr_t* bdns, mio_dns_bqr_t* qr, mio_dns_bedns_t* edns, mio_svc_dnc_on_reply_t on_reply, mio_oow_t xtnsize)
 | 
			
		||||
{
 | 
			
		||||
	/* send a request without resource records */
 | 
			
		||||
	if (bdns->rcode != MIO_DNS_RCODE_NOERROR)
 | 
			
		||||
	{
 | 
			
		||||
		mio_seterrnum (dnc->mio, MIO_EINVAL);
 | 
			
		||||
		return MIO_NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return mio_svc_dnc_sendmsg(dnc, bdns, qr, 1, MIO_NULL, 0, edns, on_reply, xtnsize);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* ----------------------------------------------------------------------- */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct dnc_dns_msg_resolve_xtn_t
 | 
			
		||||
{
 | 
			
		||||
	mio_dns_rrt_t qtype;
 | 
			
		||||
	int flags;
 | 
			
		||||
	mio_svc_dnc_on_resolve_t on_resolve;
 | 
			
		||||
};
 | 
			
		||||
typedef struct dnc_dns_msg_resolve_xtn_t dnc_dns_msg_resolve_xtn_t;
 | 
			
		||||
 | 
			
		||||
#if defined(MIO_HAVE_INLINE)
 | 
			
		||||
	static MIO_INLINE dnc_dns_msg_resolve_xtn_t* dnc_dns_msg_resolve_getxtn(mio_dns_msg_t* msg) { return ((dnc_dns_msg_resolve_xtn_t*)((mio_uint8_t*)dnc_dns_msg_getxtn(msg) + MIO_SIZEOF(dnc_dns_msg_xtn_t))); }
 | 
			
		||||
#else
 | 
			
		||||
#	define dnc_dns_msg_resolve_getxtn(msg) ((dnc_dns_msg_resolve_xtn_t*)((mio_uint8_t*)dnc_dns_msg_getxtn(msg) + MIO_SIZEOF(dnc_dns_msg_xtn_t)))
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static void on_dnc_resolve (mio_svc_dnc_t* dnc, mio_dns_msg_t* reqmsg, mio_errnum_t status, const void* data, mio_oow_t dlen)
 | 
			
		||||
{
 | 
			
		||||
	mio_t* mio = mio_svc_dnc_getmio(dnc);
 | 
			
		||||
	mio_dns_pkt_t* pkt;
 | 
			
		||||
	mio_dns_pkt_info_t* pi = MIO_NULL;
 | 
			
		||||
	dnc_dns_msg_resolve_xtn_t* reqmsgxtn = dnc_dns_msg_resolve_getxtn(reqmsg);
 | 
			
		||||
 | 
			
		||||
	if (!(reqmsgxtn->flags & MIO_SVC_DNC_RESOLVE_FLAG_BRIEF))
 | 
			
		||||
	{
 | 
			
		||||
		/* the full reply packet is requested. no transformation is required */
 | 
			
		||||
		if (reqmsgxtn->on_resolve) reqmsgxtn->on_resolve(dnc, reqmsg, status, data, dlen);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (data)
 | 
			
		||||
	{
 | 
			
		||||
		mio_uint32_t i;
 | 
			
		||||
 | 
			
		||||
		MIO_ASSERT (mio, status == MIO_ENOERR);
 | 
			
		||||
 | 
			
		||||
		pi = mio_dns_make_packet_info(mio, data, dlen);
 | 
			
		||||
		if (!pi)
 | 
			
		||||
		{
 | 
			
		||||
			status = mio_geterrnum(mio);
 | 
			
		||||
			goto no_valid_reply;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (pi->hdr.rcode != MIO_DNS_RCODE_NOERROR) 
 | 
			
		||||
		{
 | 
			
		||||
			status = MIO_EINVAL;
 | 
			
		||||
			goto no_valid_reply;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (pi->ancount < 0) goto no_valid_reply;
 | 
			
		||||
 | 
			
		||||
		/* in the brief mode, we inspect the answer section only */
 | 
			
		||||
		if (reqmsgxtn->qtype == MIO_DNS_RRT_Q_ANY)
 | 
			
		||||
		{
 | 
			
		||||
			/* return A or AAAA for ANY in the brief mode */
 | 
			
		||||
			for (i = 0; i < pi->ancount; i++)
 | 
			
		||||
			{
 | 
			
		||||
				if (pi->rr.an[i].rrtype == MIO_DNS_RRT_A || pi->rr.an[i].rrtype == MIO_DNS_RRT_AAAA)
 | 
			
		||||
				{
 | 
			
		||||
				match_found:
 | 
			
		||||
					if (reqmsgxtn->on_resolve) reqmsgxtn->on_resolve (dnc, reqmsg, status, &pi->rr.an[i], MIO_SIZEOF(pi->rr.an[i]));
 | 
			
		||||
					goto done;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for (i = 0; i < pi->ancount; i++)
 | 
			
		||||
		{
 | 
			
		||||
			/* it is a bit time taking to retreive the query type from the packet
 | 
			
		||||
			 * bundled in reqmsg as it requires parsing of the packet. let me use
 | 
			
		||||
			 * the query type i stored in the extension space. */
 | 
			
		||||
			switch (reqmsgxtn->qtype)
 | 
			
		||||
			{
 | 
			
		||||
				case MIO_DNS_RRT_Q_ANY: 
 | 
			
		||||
				case MIO_DNS_RRT_Q_AFXR: /* AFXR doesn't make sense in the brief mode. just treat it like ANY */
 | 
			
		||||
					/* no A or AAAA found. so give the first entry in the answer */
 | 
			
		||||
					goto match_found;
 | 
			
		||||
 | 
			
		||||
				case MIO_DNS_RRT_Q_MAILA:
 | 
			
		||||
					/* if you want to get the full RRs, don't use the brief mode. */
 | 
			
		||||
					if (pi->rr.an[i].rrtype == MIO_DNS_RRT_MD || pi->rr.an[i].rrtype == MIO_DNS_RRT_MF) goto match_found;
 | 
			
		||||
					break;
 | 
			
		||||
 | 
			
		||||
				case MIO_DNS_RRT_Q_MAILB:
 | 
			
		||||
					/* if you want to get the full RRs, don't use the brief mode. */
 | 
			
		||||
					if (pi->rr.an[i].rrtype == MIO_DNS_RRT_MB || pi->rr.an[i].rrtype == MIO_DNS_RRT_MG ||
 | 
			
		||||
					    pi->rr.an[i].rrtype == MIO_DNS_RRT_MR || pi->rr.an[i].rrtype == MIO_DNS_RRT_MINFO) goto match_found;
 | 
			
		||||
					break;
 | 
			
		||||
 | 
			
		||||
				default:
 | 
			
		||||
					if (pi->rr.an[i].rrtype == reqmsgxtn->qtype) goto match_found;
 | 
			
		||||
					break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		goto no_valid_reply;
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
	no_valid_reply:
 | 
			
		||||
		if (reqmsgxtn->on_resolve) reqmsgxtn->on_resolve (dnc, reqmsg, status, MIO_NULL, 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
done:
 | 
			
		||||
	if (pi) mio_dns_free_packet_info(mio_svc_dnc_getmio(dnc), pi);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
mio_dns_msg_t* mio_svc_dnc_resolve (mio_svc_dnc_t* dnc, const mio_bch_t* qname, mio_dns_rrt_t qtype, int flags, mio_svc_dnc_on_resolve_t on_resolve, mio_oow_t xtnsize)
 | 
			
		||||
{
 | 
			
		||||
	static mio_dns_bhdr_t qhdr =
 | 
			
		||||
	{
 | 
			
		||||
		-1, /* id */
 | 
			
		||||
		0,  /* qr */
 | 
			
		||||
		MIO_DNS_OPCODE_QUERY, /* opcode */
 | 
			
		||||
		0, /* aa */
 | 
			
		||||
		0, /* tc */
 | 
			
		||||
		1, /* rd */
 | 
			
		||||
		0, /* ra */
 | 
			
		||||
		0, /* ad */
 | 
			
		||||
		0, /* cd */
 | 
			
		||||
		MIO_DNS_RCODE_NOERROR /* rcode */
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	static mio_dns_bedns_t qedns =
 | 
			
		||||
	{
 | 
			
		||||
		4096, /* uplen */
 | 
			
		||||
 | 
			
		||||
		0,    /* edns version */
 | 
			
		||||
		0,    /* dnssec ok */
 | 
			
		||||
 | 
			
		||||
		0,    /* number of edns options */
 | 
			
		||||
		MIO_NULL
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	mio_dns_bqr_t qr;
 | 
			
		||||
	mio_dns_msg_t* reqmsg;
 | 
			
		||||
	dnc_dns_msg_resolve_xtn_t* reqmsgxtn;
 | 
			
		||||
 | 
			
		||||
	qr.qname = (mio_bch_t*)qname;
 | 
			
		||||
	qr.qtype = qtype;
 | 
			
		||||
	qr.qclass = MIO_DNS_RRC_IN;
 | 
			
		||||
 | 
			
		||||
	reqmsg = mio_svc_dnc_sendmsg(dnc, &qhdr, &qr, 1, MIO_NULL, 0, &qedns, on_dnc_resolve, MIO_SIZEOF(*reqmsgxtn) + xtnsize);
 | 
			
		||||
	if (reqmsg)
 | 
			
		||||
	{
 | 
			
		||||
		reqmsgxtn = dnc_dns_msg_resolve_getxtn(reqmsg);
 | 
			
		||||
		reqmsgxtn->on_resolve = on_resolve;
 | 
			
		||||
		reqmsgxtn->qtype = qtype;
 | 
			
		||||
		reqmsgxtn->flags = flags;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return reqmsg;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* ----------------------------------------------------------------------- */
 | 
			
		||||
 | 
			
		||||
static int parse_domain_name (mio_t* mio, mio_dns_pkt_info_t* pi)
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user