diff --git a/mio/bin/t01.c b/mio/bin/t01.c index 082fc34..ab65a22 100644 --- a/mio/bin/t01.c +++ b/mio/bin/t01.c @@ -1033,7 +1033,7 @@ for (i = 0; i < 5; i++) #endif -if (!mio_svc_dnc_resolve(dnc, "a.wild.com", MIO_DNS_RRT_A, 0, on_dnc_resolve, 0)) +if (!mio_svc_dnc_resolve(dnc, "b.wild.com", MIO_DNS_RRT_A, 0, on_dnc_resolve, 0)) { printf ("resolve attempt failure ---> a.wild.com\n"); } diff --git a/mio/lib/dns-cli.c b/mio/lib/dns-cli.c index d178811..8dffaba 100644 --- a/mio/lib/dns-cli.c +++ b/mio/lib/dns-cli.c @@ -56,7 +56,6 @@ struct mio_svc_dnc_t struct dnc_sck_xtn_t { mio_svc_dnc_t* dnc; - mio_dns_msg_t* reqmsg; /* used when switching to TCP from UDP for truncation */ }; typedef struct dnc_sck_xtn_t dnc_sck_xtn_t; @@ -64,7 +63,7 @@ typedef struct dnc_sck_xtn_t dnc_sck_xtn_t; struct dnc_dns_msg_xtn_t { - mio_dev_t* dev; + mio_dev_sck_t* dev; mio_tmridx_t rtmridx; mio_dns_msg_t* prev; mio_dns_msg_t* next; @@ -130,68 +129,61 @@ static int on_tcp_read (mio_dev_sck_t* dev, const void* data, mio_iolen_t dlen, { mio_t* mio = dev->mio; mio_svc_dnc_t* dnc = ((dnc_sck_xtn_t*)mio_dev_sck_getxtn(dev))->dnc; - mio_dns_msg_t* reqmsg = ((dnc_sck_xtn_t*)mio_dev_sck_getxtn(dev))->reqmsg; - dnc_dns_msg_xtn_t* reqmsgxtn = dnc_dns_msg_getxtn(reqmsg); + mio_dns_msg_t* reqmsg; mio_dns_pkt_t* pkt; mio_uint16_t id; -// mio_dns_pkt_t* pkt; - mio_errnum_t status; - if (MIO_UNLIKELY(dlen <= -1)) { - status = mio_geterrnum(mio); MIO_DEBUG1 (mio, "dns tcp read error ....%js\n", mio_geterrmsg(mio)); /* TODO: add source packet */ - goto finalize; + goto oops; } - else if (dlen == 0) + else if (MIO_UNLIKELY(dlen == 0)) { - status = MIO_EDEVHUP; MIO_DEBUG0 (mio, "dns tcp read error ...premature socket hangul\n"); /* TODO: add source packet */ - goto finalize; + goto oops; } -/* assemble the first two bytes. - * read as many as those two bytes.. */ - -#if 0 - if (MIO_UNLIKELY(dlen < MIO_SIZEOF(*pkt))) +/* TODO: assemble the first two bytes. + * read as many as those two bytes.. + * the following code is wrong.. */ + if (MIO_UNLIKELY(dlen < MIO_SIZEOF(*pkt) + 2)) { - status = MIO_E MIO_DEBUG0 (mio, "dns packet too small from ....\n"); /* TODO: add source packet */ + goto oops; /* mut not be an error. buffer it futher... */ } - pkt = (mio_dns_pkt_t*)data; + + pkt = (mio_dns_pkt_t*)((mio_uint8_t*)data + 2); if (!pkt->qr) { MIO_DEBUG0 (mio, "dropping dns request received ...\n"); /* TODO: add source info */ + return 0; /* drop request. nothing to do */ } - //id = mio_ntoh16(pkt->id); -#endif -MIO_DEBUG0 (mio, "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); + id = mio_ntoh16(pkt->id); -// must not read it this way... - if (reqmsgxtn->rtmridx != MIO_TMRIDX_INVALID) +MIO_DEBUG1 (mio, "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>id [%d] >>>>>>>>>>>>>>>>>>\n", id); + + reqmsg = dnc->pending_req; + while (reqmsg) { - /* unschedule a timer job if any */ - mio_deltmrjob (mio, reqmsgxtn->rtmridx); - MIO_ASSERT (mio, reqmsgxtn->rtmridx == MIO_TMRIDX_INVALID); + 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) + { + if (MIO_LIKELY(reqmsgxtn->on_done)) reqmsgxtn->on_done (dnc, reqmsg, MIO_ENOERR, pkt, dlen - 2); + release_dns_msg (dnc, reqmsg); + return 0; + } + + reqmsg = reqmsgxtn->next; } - if (MIO_LIKELY(reqmsgxtn->on_done)) - { - reqmsgxtn->on_done (dnc, reqmsg, MIO_ENOERR, (mio_uint8_t*)data + 2, dlen - 2); - reqmsgxtn->on_done = MIO_NULL; - } - mio_dev_sck_halt(dev); +MIO_DEBUG1 (mio, "unknown dns response over tcp... %d\n", pkt->id); /* TODO: add source info */ return 0; -finalize: - if (MIO_LIKELY(reqmsgxtn->on_done)) - { - reqmsgxtn->on_done (dnc, reqmsg, status, MIO_NULL, 0); - reqmsgxtn->on_done = MIO_NULL; - } +oops: mio_dev_sck_halt(dev); return 0; } @@ -199,21 +191,17 @@ finalize: static void on_tcp_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; + dnc_dns_msg_xtn_t* reqmsgxtn = dnc_dns_msg_getxtn(reqmsg); + mio_dev_sck_t* dev = reqmsgxtn->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_ASSERT (mio, reqmsgxtn->rtmridx == MIO_TMRIDX_INVALID); MIO_ASSERT (mio, dev == dnc->tcp_sck); MIO_DEBUG0 (mio, "*** TIMEOUT ==> unable to receive dns response in time over TCP...\n"); - if (MIO_LIKELY(msgxtn->on_done)) - { - msgxtn->on_done (dnc, reqmsg, MIO_ETMOUT, MIO_NULL, 0); - msgxtn->on_done = MIO_NULL; - } - mio_dev_sck_halt(dev); + if (MIO_LIKELY(reqmsgxtn->on_done)) reqmsgxtn->on_done (dnc, reqmsg, MIO_ETMOUT, MIO_NULL, 0); + release_dns_msg (dnc, reqmsg); } static int on_tcp_write (mio_dev_sck_t* dev, mio_iolen_t wrlen, void* wrctx, const mio_skad_t* dstaddr) @@ -252,6 +240,7 @@ static int on_tcp_write (mio_dev_sck_t* dev, mio_iolen_t wrlen, void* wrctx, con } else { + /* no error. successfuly sent a message. no reply is expected */ status = MIO_ENOERR; goto finalize; } @@ -259,42 +248,52 @@ static int on_tcp_write (mio_dev_sck_t* dev, mio_iolen_t wrlen, void* wrctx, con return 0; finalize: - if (MIO_LIKELY(msgxtn->on_done)) - { - msgxtn->on_done (dnc, msg, status, MIO_NULL, 0); - msgxtn->on_done = MIO_NULL; - } - mio_dev_sck_halt (dev); + if (MIO_LIKELY(msgxtn->on_done)) msgxtn->on_done (dnc, msg, status, MIO_NULL, 0); + release_dns_msg (dnc, msg); return 0; } +static void write_dns_msg_over_tcp (mio_dev_sck_t* dev, mio_dns_msg_t* msg) +{ + mio_t* mio = dev->mio; + mio_svc_dnc_t* dnc = ((dnc_sck_xtn_t*)mio_dev_sck_getxtn(dev))->dnc; + dnc_dns_msg_xtn_t* msgxtn = dnc_dns_msg_getxtn(msg); + mio_uint16_t pktlen; + mio_iovec_t iov[2]; + + pktlen = mio_hton16(msg->pktlen); + + MIO_ASSERT (mio, msgxtn->rtries == 0); + msgxtn->rtries = 1; /* this is the first send. however, there will be no retries over tcp */ + + /* TODO: Is it better to create 2 byte space when sending UDP and use it here instead of iov? */ + iov[0].iov_ptr = &pktlen; + iov[0].iov_len = MIO_SIZEOF(pktlen); + iov[1].iov_ptr = mio_dns_msg_to_pkt(msg); + iov[1].iov_len = msg->pktlen; + if (mio_dev_sck_timedwritev(dev, iov, MIO_COUNTOF(iov), &msgxtn->rtmout, msg, MIO_NULL) <= -1) + { + if (MIO_LIKELY(msgxtn->on_done)) msgxtn->on_done (dnc, msg, mio_geterrnum(mio), MIO_NULL, 0); + release_dns_msg (dnc, msg); + } +} static void on_tcp_connect (mio_dev_sck_t* dev) { mio_t* mio = dev->mio; mio_svc_dnc_t* dnc = ((dnc_sck_xtn_t*)mio_dev_sck_getxtn(dev))->dnc; - mio_dns_msg_t* reqmsg = ((dnc_sck_xtn_t*)mio_dev_sck_getxtn(dev))->reqmsg; - dnc_dns_msg_xtn_t* reqmsgxtn = dnc_dns_msg_getxtn(reqmsg); - mio_uint16_t pktlen; - mio_iovec_t iov[2]; + mio_dns_msg_t* reqmsg; MIO_ASSERT (mio, dev == dnc->tcp_sck); - pktlen = mio_hton16(reqmsg->pktlen); - -/* TODO: Is it better to create 2 byte space when sending UDP and use it here instead of iov? */ - iov[0].iov_ptr = &pktlen; - iov[0].iov_len = MIO_SIZEOF(pktlen); - iov[1].iov_ptr = mio_dns_msg_to_pkt(reqmsg); - iov[1].iov_len = reqmsg->pktlen; - if (mio_dev_sck_timedwritev(dev, iov, MIO_COUNTOF(iov), &reqmsgxtn->rtmout, reqmsg, MIO_NULL) <= -1) + reqmsg = dnc->pending_req; + while (reqmsg) { - if (MIO_LIKELY(reqmsgxtn->on_done)) - { - reqmsgxtn->on_done (dnc, reqmsg, mio_geterrnum(mio), MIO_NULL, 0); - reqmsgxtn->on_done = MIO_NULL; - } - mio_dev_sck_halt (dev); + dnc_dns_msg_xtn_t* reqmsgxtn = dnc_dns_msg_getxtn(reqmsg); + mio_dns_msg_t* nextreqmsg = reqmsgxtn->next; + + if (reqmsgxtn->dev == dev && reqmsgxtn->rtries <= 0) write_dns_msg_over_tcp (dev, reqmsg); + reqmsg = nextreqmsg; } } @@ -302,12 +301,10 @@ static void on_tcp_disconnect (mio_dev_sck_t* dev) { mio_t* mio = dev->mio; mio_svc_dnc_t* dnc = ((dnc_sck_xtn_t*)mio_dev_sck_getxtn(dev))->dnc; - mio_dns_msg_t* reqmsg = ((dnc_sck_xtn_t*)mio_dev_sck_getxtn(dev))->reqmsg; - dnc_dns_msg_xtn_t* reqmsgxtn = dnc_dns_msg_getxtn(reqmsg); + mio_dns_msg_t* reqmsg; int status; /* UNABLE TO CONNECT or CONNECT TIMED OUT */ - status = mio_geterrnum(mio); if (status == MIO_ENOERR) @@ -319,9 +316,20 @@ static void on_tcp_disconnect (mio_dev_sck_t* dev) MIO_DEBUG2 (mio, "TCP UNABLED TO CONNECT %d -> %js\n", status, mio_errnum_to_errstr(status)); } -printf ("KILLING REQMSG %p REQMSGXTN %p\n", reqmsg, reqmsgxtn); - if (MIO_LIKELY(reqmsgxtn->on_done)) reqmsgxtn->on_done (dnc, reqmsg, status, MIO_NULL, 0); - release_dns_msg (dnc, reqmsg); + reqmsg = dnc->pending_req; + while (reqmsg) + { + dnc_dns_msg_xtn_t* reqmsgxtn = dnc_dns_msg_getxtn(reqmsg); + mio_dns_msg_t* nextreqmsg = reqmsgxtn->next; + + if (reqmsgxtn->dev == dev) + { + if (MIO_LIKELY(reqmsgxtn->on_done)) reqmsgxtn->on_done (dnc, reqmsg, MIO_ENORSP, MIO_NULL, 0); + release_dns_msg (dnc, reqmsg); + } + + reqmsg = nextreqmsg; + } /* let's forget about the tcp socket */ dnc->tcp_sck = MIO_NULL; @@ -360,29 +368,35 @@ static int switch_reqmsg_transport_to_tcp (mio_svc_dnc_t* dnc, mio_dns_msg_t* re mkinfo.on_disconnect = on_tcp_disconnect; dnc->tcp_sck = mio_dev_sck_make(mio, MIO_SIZEOF(*sckxtn), &mkinfo); if (!dnc->tcp_sck) return -1; + + sckxtn = (dnc_sck_xtn_t*)mio_dev_sck_getxtn(dnc->tcp_sck); + sckxtn->dnc = dnc; + + MIO_MEMSET (&cinfo, 0, MIO_SIZEOF(cinfo)); + cinfo.remoteaddr = reqmsgxtn->servaddr; + cinfo.connect_tmout = reqmsgxtn->rtmout; /* TOOD: create a separate connect timeout or treate rtmout as a whole transaction time and calculate the remaining time from the transaction start, and use it */ + + if (mio_dev_sck_connect(dnc->tcp_sck, &cinfo) <= -1) + { + mio_dev_sck_kill (dnc->tcp_sck); + dnc->tcp_sck = MIO_NULL; + return -1; /* the connect request hasn't been honored. */ + } } - - sckxtn = (dnc_sck_xtn_t*)mio_dev_sck_getxtn(dnc->tcp_sck); - sckxtn->dnc = dnc; - sckxtn->reqmsg = reqmsg; - - MIO_MEMSET (&cinfo, 0, MIO_SIZEOF(cinfo)); - cinfo.remoteaddr = reqmsgxtn->servaddr; - cinfo.connect_tmout = reqmsgxtn->rtmout; /* TOOD: create a separate connect timeout or treate rtmout as a whole transaction time and calculate the remaining time from the transaction start, and use it */ - - if (mio_dev_sck_connect(dnc->tcp_sck, &cinfo) <= -1) - { - mio_dev_sck_kill (dnc->tcp_sck); - dnc->tcp_sck = MIO_NULL; - return -1; /* the connect request hasn't been honored. */ - } - + /* switch the belonging device to the tcp socket since the connect request has been acknowledged. */ MIO_ASSERT (mio, reqmsgxtn->rtmridx == MIO_TMRIDX_INVALID); /* ensure no timer job scheduled at this moment */ - reqmsgxtn->dev = (mio_dev_t*)dnc->tcp_sck; - reqmsgxtn->rtries = 0; /* i don't retry with tcp. so reset this to 0 */ + reqmsgxtn->dev = dnc->tcp_sck; + reqmsgxtn->rtries = 0; printf ("SWITCHED >>>>>>>>>>>>>>>>> %p %p %p %p %p\n", reqmsg, reqmsgxtn, reqmsgxtn->dev, dnc->udp_sck, dnc->tcp_sck); + + if (MIO_DEV_SCK_GET_PROGRESS(dnc->tcp_sck) & MIO_DEV_SCK_CONNECTED) + { + write_dns_msg_over_tcp (reqmsgxtn->dev, reqmsg); + /* the caller must not use reqmsg from now because write_dns_msg_over_tcp() may release 'reqmsg' */ + } + return 0; } @@ -425,9 +439,8 @@ static int on_udp_read (mio_dev_sck_t* dev, const void* data, mio_iolen_t dlen, 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 (reqmsgxtn->dev == dev && pkt->id == reqpkt->id && mio_equal_skads(&reqmsgxtn->servaddr, srcaddr, 0)) { -printf ("MATCHED >>>>>>>>>>>>>>>>> %p %p %p %p %p\n", reqmsg, reqmsgxtn, reqmsgxtn->dev, dnc->udp_sck, dnc->tcp_sck); if (reqmsgxtn->rtmridx != MIO_TMRIDX_INVALID) { /* unschedule a timer job if any */ @@ -441,7 +454,7 @@ pkt->tc = 1; if (MIO_UNLIKELY(pkt->tc)) { /* TODO: add an option for this behavior */ - if (switch_reqmsg_transport_to_tcp(dnc, reqmsg) >= 0) { printf ("SWITCHING OK...\n"); return 0; } + if (switch_reqmsg_transport_to_tcp(dnc, reqmsg) >= 0) return 0; /* TODO: add an option to call an error callback with TRUNCATION error code instead of fallback to received UDP truncated message */ } @@ -463,7 +476,7 @@ static void on_udp_reply_timeout (mio_t* mio, const mio_ntime_t* now, mio_tmrjob { 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_dev_sck_t* dev = msgxtn->dev; mio_svc_dnc_t* dnc = ((dnc_sck_xtn_t*)mio_dev_sck_getxtn(dev))->dnc; mio_errnum_t status = MIO_ETMOUT; @@ -555,6 +568,24 @@ static void on_udp_connect (mio_dev_sck_t* dev) static void on_udp_disconnect (mio_dev_sck_t* dev) { + mio_t* mio = dev->mio; + mio_svc_dnc_t* dnc = ((dnc_sck_xtn_t*)mio_dev_sck_getxtn(dev))->dnc; + mio_dns_msg_t* reqmsg; + + reqmsg = dnc->pending_req; + while (reqmsg) + { + dnc_dns_msg_xtn_t* reqmsgxtn = dnc_dns_msg_getxtn(reqmsg); + mio_dns_msg_t* nextreqmsg = reqmsgxtn->next; + + if (reqmsgxtn->dev == dev) + { + if (MIO_LIKELY(reqmsgxtn->on_done)) reqmsgxtn->on_done (dnc, reqmsg, MIO_ENORSP, MIO_NULL, 0); + release_dns_msg (dnc, reqmsg); + } + + reqmsg = nextreqmsg; + } } 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) @@ -647,7 +678,7 @@ mio_dns_msg_t* mio_svc_dnc_sendmsg (mio_svc_dnc_t* dnc, mio_dns_bhdr_t* bdns, mi } msgxtn = dnc_dns_msg_getxtn(msg); - msgxtn->dev = (mio_dev_t*)dnc->udp_sck; + msgxtn->dev = dnc->udp_sck; msgxtn->rtmridx = MIO_TMRIDX_INVALID; msgxtn->on_done = on_done; msgxtn->wtmout = dnc->send_tmout; diff --git a/mio/lib/err.c b/mio/lib/err.c index c4b9299..69a88ac 100644 --- a/mio/lib/err.c +++ b/mio/lib/err.c @@ -55,9 +55,10 @@ static mio_ooch_t errstr_24[] = {'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n static mio_ooch_t errstr_25[] = {'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', ' ', 'r', 'e', 's', 'e', 't', '\0' }; static mio_ooch_t errstr_26[] = {'n', 'o', ' ', 'c', 'a', 'p', 'a', 'b', 'i', 'l', 'i', 't', 'y', '\0' }; static mio_ooch_t errstr_27[] = {'t', 'i', 'm', 'e', 'd', ' ', 'o', 'u', 't', '\0' }; -static mio_ooch_t errstr_28[] = {'u', 'n', 'a', 'b', 'l', 'e', ' ', 't', 'o', ' ', 'm', 'a', 'k', 'e', ' ', 'd', 'e', 'v', 'i', 'c', 'e', '\0' }; -static mio_ooch_t errstr_29[] = {'d', 'e', 'v', 'i', 'c', 'e', ' ', 'e', 'r', 'r', 'o', 'r', '\0' }; -static mio_ooch_t errstr_30[] = {'d', 'e', 'v', 'i', 'c', 'e', ' ', 'h', 'a', 'n', 'g', '-', 'u', 'p', '\0' }; +static mio_ooch_t errstr_28[] = {'n', 'o', ' ', 'r', 'e', 's', 'p', 'o', 'n', 's', 'e', '\0' }; +static mio_ooch_t errstr_29[] = {'u', 'n', 'a', 'b', 'l', 'e', ' ', 't', 'o', ' ', 'm', 'a', 'k', 'e', ' ', 'd', 'e', 'v', 'i', 'c', 'e', '\0' }; +static mio_ooch_t errstr_30[] = {'d', 'e', 'v', 'i', 'c', 'e', ' ', 'e', 'r', 'r', 'o', 'r', '\0' }; +static mio_ooch_t errstr_31[] = {'d', 'e', 'v', 'i', 'c', 'e', ' ', 'h', 'a', 'n', 'g', '-', 'u', 'p', '\0' }; static mio_ooch_t* errstr[] = { errstr_0, errstr_1, errstr_2, errstr_3, errstr_4, @@ -66,7 +67,7 @@ static mio_ooch_t* errstr[] = errstr_15, errstr_16, errstr_17, errstr_18, errstr_19, errstr_20, errstr_21, errstr_22, errstr_23, errstr_24, errstr_25, errstr_26, errstr_27, errstr_28, errstr_29, - errstr_30 + errstr_30, errstr_31 }; /* -------------------------------------------------------------------------- diff --git a/mio/lib/mio.h b/mio/lib/mio.h index cf5916c..d6cf363 100644 --- a/mio/lib/mio.h +++ b/mio/lib/mio.h @@ -105,6 +105,7 @@ enum mio_errnum_t MIO_ECONRS, /**< connection reset */ MIO_ENOCAPA, /**< no capability */ MIO_ETMOUT, /**< timed out */ + MIO_ENORSP, /**< no response */ MIO_EDEVMAKE, /**< unable to make device */ MIO_EDEVERR, /**< device error */