diff --git a/mio/bin/t01.c b/mio/bin/t01.c
index a51129b..df03cd1 100644
--- a/mio/bin/t01.c
+++ b/mio/bin/t01.c
@@ -608,7 +608,6 @@ static void on_dnc_resolve(mio_svc_dnc_t* dnc, mio_dns_msg_t* reqmsg, mio_errnum
 {
 	mio_dns_pkt_info_t* pi = MIO_NULL;
 
-
 	if (data) // status == MIO_ENOERR
 	{
 		mio_uint32_t i;
@@ -660,7 +659,7 @@ static void on_dnc_resolve(mio_svc_dnc_t* dnc, mio_dns_msg_t* reqmsg, mio_errnum
 	{
 	no_valid_reply:
 		if (status == MIO_ETMOUT) printf ("XXXXXXXXXXXXXXXX TIMED OUT XXXXXXXXXXXXXXXXX\n");
-		else printf ("XXXXXXXXXXXXXXXXx NO REPLY XXXXXXXXXXXXXXXXXXXXXXXXX\n");
+		else printf ("XXXXXXXXXXXXXXXXx NO VALID REPLY XXXXXXXXXXXXXXXXXXXXXXXXX\n");
 	}
 
 done:
@@ -698,6 +697,10 @@ static void on_dnc_resolve_brief (mio_svc_dnc_t* dnc, mio_dns_msg_t* reqmsg, mio
 		{
 			printf ("^^^ SIMPLE -> NS [%s] %d\n", brr->dptr, (int)brr->dlen);
 		}
+		else if (brr->rrtype == MIO_DNS_RRT_PTR)
+		{
+			printf ("^^^ SIMPLE -> PTR [%s] %d\n", brr->dptr, (int)brr->dlen);
+		}
 		else if (brr->rrtype == MIO_DNS_RRT_SOA)
 		{
 			mio_dns_brrd_soa_t* soa = brr->dptr;
@@ -711,7 +714,7 @@ static void on_dnc_resolve_brief (mio_svc_dnc_t* dnc, mio_dns_msg_t* reqmsg, mio
 	else
 	{
 		if (status == MIO_ETMOUT) printf ("QQQQQQQQQQQQQQQQQQQ TIMED OUT QQQQQQQQQQQQQQQQQ\n");
-		else printf ("QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ NO REPLY QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQq\n");
+		else printf ("QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ NO VALID REPLY QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQq - %d\n", mio_geterrnum(mio_svc_dnc_getmio(dnc)));
 	}
 }
 
@@ -1014,6 +1017,11 @@ if (!mio_svc_dnc_resolve(dnc, "code.miflux.com", MIO_DNS_RRT_A, MIO_SVC_DNC_RESO
 	printf ("resolve attempt failure ---> code.miflux.com\n");
 }
 
+if (!mio_svc_dnc_resolve(dnc, "1.1.1.1.in-addr.arpa", MIO_DNS_RRT_PTR, MIO_SVC_DNC_RESOLVE_FLAG_BRIEF, on_dnc_resolve_brief, 0))
+{
+	printf ("resolve attempt failure ---> 1.1.1.1.in-addr.arpa\n");
+}
+
 //if (!mio_svc_dnc_resolve(dnc, "ipv6.google.com", MIO_DNS_RRT_AAAA, MIO_SVC_DNC_RESOLVE_FLAG_BRIEF, on_dnc_resolve_brief, 0))
 if (!mio_svc_dnc_resolve(dnc, "google.com", MIO_DNS_RRT_SOA, MIO_SVC_DNC_RESOLVE_FLAG_BRIEF, on_dnc_resolve_brief, 0))
 //if (!mio_svc_dnc_resolve(dnc, "google.com", MIO_DNS_RRT_NS, MIO_SVC_DNC_RESOLVE_FLAG_BRIEF, on_dnc_resolve_brief, 0))
diff --git a/mio/lib/dns.c b/mio/lib/dns.c
index 1f0e946..6da7e1d 100644
--- a/mio/lib/dns.c
+++ b/mio/lib/dns.c
@@ -221,7 +221,7 @@ static int dnc_on_read (mio_dev_sck_t* dev, const void* data, mio_iolen_t dlen,
 	mio_dns_msg_t* reqmsg;
 	mio_uint16_t id;
 
-	if (dlen < MIO_SIZEOF(*pkt)) 
+	if (MIO_UNLIKELY(dlen < MIO_SIZEOF(*pkt))) 
 	{
 		MIO_DEBUG0 (mio, "dns packet too small from ....\n"); /* TODO: add source packet */
 		return 0; /* drop */
@@ -450,21 +450,6 @@ mio_dns_msg_t* mio_svc_dnc_sendmsg (mio_svc_dnc_t* dnc, mio_dns_bhdr_t* bdns, mi
 	return msg;
 }
 
-#if 0
-mio_dns_msg_t* mio_svc_dnc_resendmsg (mio_svc_dnc_t* dnc, mio_dns_msg_t* msg)
-{
-	if (mio_dev_sck_write(dnc->sck, mio_dns_msg_to_pkt(msg), msg->pktlen, msg, &dnc->serveraddr) <= -1)
-	{
-		release_dns_msg (dnc, msg);
-		return MIO_NULL;
-	}
-
-	msg->no_release = 1; ????
-	return msg;
-}
-#endif
-
-
 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 */
@@ -497,9 +482,17 @@ typedef struct dnc_dns_msg_resolve_xtn_t dnc_dns_msg_resolve_xtn_t;
 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);
 
+	MIO_ASSERT (mio, dlen >= MIO_SIZEOF(*pkt)); /* this is guaranteed by the dnc_on_read() */
+	pkt = (mio_dns_pkt_t*)data;
+	if (pkt->tc && (reqmsgxtn->flags & MIO_SVC_DNC_RESOLVE_FLAG_TCP_IF_TC)) /* truncated */
+	{
+		/* TODO: */
+	}
+
 	if (!(reqmsgxtn->flags & MIO_SVC_DNC_RESOLVE_FLAG_BRIEF))
 	{
 		/* the full reply packet is requested. no transformation is required */
@@ -799,11 +792,12 @@ static int parse_answer_rr (mio_t* mio, mio_dns_rr_part_t rr_part, mio_oow_t pos
 
 		case MIO_DNS_RRT_CNAME:
 		case MIO_DNS_RRT_NS:
+		case MIO_DNS_RRT_PTR:
 		{
 		#if !defined(MIO_BUILD_RELEASE)
 			mio_uint8_t* xptr = pi->_ptr;
 		#endif
-			if (parse_domain_name(mio, pi) <= -1) return -1;
+			if (parse_domain_name(mio, pi) <= -1) goto oops;
 			MIO_ASSERT (mio, pi->_ptr == xptr + dlen);
 			break;
 		}
@@ -822,10 +816,10 @@ static int parse_answer_rr (mio_t* mio, mio_dns_rr_part_t rr_part, mio_oow_t pos
 				pi->_rrdptr += MIO_SIZEOF(*soa);
 
 				soa->mname = (mio_bch_t*)pi->_rrdptr;
-				if (parse_domain_name(mio, pi) <= -1) return -1;
+				if (parse_domain_name(mio, pi) <= -1) goto oops;
 
 				soa->rname = (mio_bch_t*)pi->_rrdptr;
-				if (parse_domain_name(mio, pi) <= -1) return -1;
+				if (parse_domain_name(mio, pi) <= -1) goto oops;
 
 				MIO_MEMCPY (&soa->serial, pi->_ptr, 20);
 				soa->serial = mio_ntoh32(soa->serial);
@@ -836,9 +830,10 @@ static int parse_answer_rr (mio_t* mio, mio_dns_rr_part_t rr_part, mio_oow_t pos
 			}
 			else
 			{
-				if (parse_domain_name(mio, pi) <= -1) return -1;
-				if (parse_domain_name(mio, pi) <= -1) return -1;
+				if (parse_domain_name(mio, pi) <= -1) goto oops;
+				if (parse_domain_name(mio, pi) <= -1) goto oops;
 			}
+			if (MIO_UNLIKELY(pi->_end - pi->_ptr) < 20) goto oops;
  			pi->_ptr += 20;
 
 			MIO_ASSERT (mio, pi->_ptr == xptr + dlen);
@@ -966,14 +961,13 @@ void mio_dns_free_packet_info (mio_t* mio, mio_dns_pkt_info_t* pi)
 
 /* ----------------------------------------------------------------------- */
 
-static mio_oow_t encode_rdata_in_dns_msg (mio_t* mio, const mio_dns_brr_t* rr, mio_dns_rrtr_t* rrtr)
+static mio_oow_t encode_rrdata_in_dns_msg (mio_t* mio, const mio_dns_brr_t* rr, mio_dns_rrtr_t* rrtr)
 {
 	switch (rr->rrtype)
 	{
 		case MIO_DNS_RRT_A:
 			break;
 		case MIO_DNS_RRT_AAAA:
-		
 			break;
 
 		/*
@@ -993,6 +987,7 @@ static mio_oow_t encode_rdata_in_dns_msg (mio_t* mio, const mio_dns_brr_t* rr, m
 		case MIO_DNS_RRT_NS:
 		case MIO_DNS_RRT_PTR:
 			/* just a normal domain name */
+			/* TODO: take a null-terminated string and encode it using to_dn() */
 			break;
 
 	#if 0
@@ -1130,7 +1125,7 @@ mio_dns_msg_t* mio_dns_make_msg (mio_t* mio, mio_dns_bhdr_t* bhdr, mio_dns_bqr_t
 				rrtr->rrclass = mio_hton16(rr[i].rrclass);
 				rrtr->ttl = mio_hton32(rr[i].ttl);
 
-				rdata_len = encode_rdata_in_dns_msg(mio, &rr[i], rrtr);
+				rdata_len = encode_rrdata_in_dns_msg(mio, &rr[i], rrtr);
 				dn = (mio_uint8_t*)(rrtr + 1) + rdata_len;
 
 				match_count++;
diff --git a/mio/lib/mio-dns.h b/mio/lib/mio-dns.h
index 86caeeb..1ff2afc 100644
--- a/mio/lib/mio-dns.h
+++ b/mio/lib/mio-dns.h
@@ -391,7 +391,8 @@ typedef void (*mio_svc_dnc_on_resolve_t) (
 
 enum mio_svc_dnc_resolve_flag_t
 {
-	MIO_SVC_DNC_RESOLVE_FLAG_BRIEF = (1 << 0)
+	MIO_SVC_DNC_RESOLVE_FLAG_BRIEF     = (1 << 0),
+	MIO_SVC_DNC_RESOLVE_FLAG_TCP_IF_TC = (1 << 1)
 };
 typedef enum mio_svc_dnc_resolve_flag_t  mio_svc_dnc_resolve_flag_t;
 
diff --git a/mio/lib/mio-skad.h b/mio/lib/mio-skad.h
index 1f6c0ec..dc10c2e 100644
--- a/mio/lib/mio-skad.h
+++ b/mio/lib/mio-skad.h
@@ -67,6 +67,44 @@ typedef struct mio_skad_t mio_skad_t;
 extern "C" {
 #endif
 
+MIO_EXPORT int mio_ucharstoskad (
+	mio_t*            mio,
+	const mio_uch_t*  str,
+	mio_oow_t         len,
+	mio_skad_t*       skad
+);
+
+MIO_EXPORT int mio_bcharstoskad (
+	mio_t*            mio,
+	const mio_bch_t*  str,
+	mio_oow_t         len,
+	mio_skad_t*       skad
+);
+
+MIO_EXPORT mio_oow_t mio_skadtoucstr (
+	mio_t*            mio,
+	const mio_skad_t* skad,
+	mio_uch_t*        buf,
+	mio_oow_t         len,
+	int               flags
+);
+
+MIO_EXPORT mio_oow_t mio_skadtobcstr (
+	mio_t*            mio,
+	const mio_skad_t* skad,
+	mio_bch_t*        buf,
+	mio_oow_t         len,
+	int               flags
+);
+
+#if defined(MIO_OOCH_IS_UCH)
+#       define mio_oocharstoskad mio_ucharstoskad
+#       define mio_skadtooocstr mio_skadtoucstr
+#else
+#       define mio_oocharstoskad mio_bcharstoskad
+#       define mio_skadtooocstr mio_skadtobcstr
+#endif
+
 MIO_EXPORT int mio_skad_family (
 	const mio_skad_t* skad
 );
diff --git a/mio/lib/skad.c b/mio/lib/skad.c
index 571a8b8..5cc387b 100644
--- a/mio/lib/skad.c
+++ b/mio/lib/skad.c
@@ -62,12 +62,54 @@ union mio_skad_alt_t
 typedef union mio_skad_alt_t mio_skad_alt_t;
 
 
-static int str_to_ipv4 (const mio_ooch_t* str, mio_oow_t len, struct in_addr* inaddr)
+static int uchars_to_ipv4 (const mio_uch_t* str, mio_oow_t len, struct in_addr* inaddr)
 {
-	const mio_ooch_t* end;
+	const mio_uch_t* end;
 	int dots = 0, digits = 0;
 	mio_uint32_t acc = 0, addr = 0;
-	mio_ooch_t c;
+	mio_uch_t c;
+
+	end = str + len;
+
+	do
+	{
+		if (str >= end)
+		{
+			if (dots < 3 || digits == 0) return -1;
+			addr = (addr << 8) | acc;
+			break;
+		}
+
+		c = *str++;
+
+		if (c >= '0' && c <= '9') 
+		{
+			if (digits > 0 && acc == 0) return -1;
+			acc = acc * 10 + (c - '0');
+			if (acc > 255) return -1;
+			digits++;
+		}
+		else if (c == '.') 
+		{
+			if (dots >= 3 || digits == 0) return -1;
+			addr = (addr << 8) | acc;
+			dots++; acc = 0; digits = 0;
+		}
+		else return -1;
+	}
+	while (1);
+
+	inaddr->s_addr = mio_hton32(addr);
+	return 0;
+
+}
+
+static int bchars_to_ipv4 (const mio_bch_t* str, mio_oow_t len, struct in_addr* inaddr)
+{
+	const mio_bch_t* end;
+	int dots = 0, digits = 0;
+	mio_uint32_t acc = 0, addr = 0;
+	mio_bch_t c;
 
 	end = str + len;
 
@@ -105,14 +147,14 @@ static int str_to_ipv4 (const mio_ooch_t* str, mio_oow_t len, struct in_addr* in
 }
 
 #if (MIO_SIZEOF_STRUCT_SOCKADDR_IN6 > 0)
-static int str_to_ipv6 (const mio_ooch_t* src, mio_oow_t len, struct in6_addr* inaddr)
+static int uchars_to_ipv6 (const mio_uch_t* src, mio_oow_t len, struct in6_addr* inaddr)
 {
 	mio_uint8_t* tp, * endp, * colonp;
-	const mio_ooch_t* curtok;
-	mio_ooch_t ch;
+	const mio_uch_t* curtok;
+	mio_uch_t ch;
 	int saw_xdigit;
 	unsigned int val;
-	const mio_ooch_t* src_end;
+	const mio_uch_t* src_end;
 
 	src_end = src + len;
 
@@ -177,7 +219,117 @@ static int str_to_ipv6 (const mio_ooch_t* src, mio_oow_t len, struct in6_addr* i
 		}
 
 		if (ch == '.' && ((tp + MIO_SIZEOF(struct in_addr)) <= endp) &&
-		    str_to_ipv4(curtok, src_end - curtok, (struct in_addr*)tp) == 0) 
+		    uchars_to_ipv4(curtok, src_end - curtok, (struct in_addr*)tp) == 0) 
+		{
+			tp += MIO_SIZEOF(struct in_addr*);
+			saw_xdigit = 0;
+			break; 
+		}
+
+		return -1;
+	}
+
+	if (saw_xdigit) 
+	{
+		if (tp + MIO_SIZEOF(mio_uint16_t) > endp) return -1;
+		*tp++ = (mio_uint8_t)(val >> 8) & 0xff;
+		*tp++ = (mio_uint8_t)val & 0xff;
+	}
+	if (colonp != MIO_NULL) 
+	{
+		/*
+		 * Since some memmove()'s erroneously fail to handle
+		 * overlapping regions, we'll do the shift by hand.
+		 */
+		mio_oow_t n = tp - colonp;
+		mio_oow_t i;
+ 
+		for (i = 1; i <= n; i++) 
+		{
+			endp[-i] = colonp[n - i];
+			colonp[n - i] = 0;
+		}
+		tp = endp;
+	}
+
+	if (tp != endp) return -1;
+
+	return 0;
+}
+
+static int bchars_to_ipv6 (const mio_bch_t* src, mio_oow_t len, struct in6_addr* inaddr)
+{
+	mio_uint8_t* tp, * endp, * colonp;
+	const mio_bch_t* curtok;
+	mio_bch_t ch;
+	int saw_xdigit;
+	unsigned int val;
+	const mio_bch_t* src_end;
+
+	src_end = src + len;
+
+	MIO_MEMSET (inaddr, 0, MIO_SIZEOF(*inaddr));
+	tp = &inaddr->s6_addr[0];
+	endp = &inaddr->s6_addr[MIO_COUNTOF(inaddr->s6_addr)];
+	colonp = MIO_NULL;
+
+	/* Leading :: requires some special handling. */
+	if (src < src_end && *src == ':')
+	{
+		src++;
+		if (src >= src_end || *src != ':') return -1;
+	}
+
+	curtok = src;
+	saw_xdigit = 0;
+	val = 0;
+
+	while (src < src_end)
+	{
+		int v1;
+
+		ch = *src++;
+
+		if (ch >= '0' && ch <= '9')
+			v1 = ch - '0';
+		else if (ch >= 'A' && ch <= 'F')
+			v1 = ch - 'A' + 10;
+		else if (ch >= 'a' && ch <= 'f')
+			v1 = ch - 'a' + 10;
+		else v1 = -1;
+		if (v1 >= 0)
+		{
+			val <<= 4;
+			val |= v1;
+			if (val > 0xffff) return -1;
+			saw_xdigit = 1;
+			continue;
+		}
+
+		if (ch == ':') 
+		{
+			curtok = src;
+			if (!saw_xdigit) 
+			{
+				if (colonp) return -1;
+				colonp = tp;
+				continue;
+			}
+			else if (src >= src_end)
+			{
+				/* a colon can't be the last character */
+				return -1;
+			}
+
+			*tp++ = (mio_uint8_t)(val >> 8) & 0xff;
+			*tp++ = (mio_uint8_t)val & 0xff;
+			saw_xdigit = 0;
+			val = 0;
+			continue;
+		}
+
+		if (ch == '.' && ((tp + MIO_SIZEOF(struct in_addr)) <= endp) &&
+		    bchars_to_ipv4(curtok, src_end - curtok, (struct in_addr*)tp) == 0) 
 		{
 			tp += MIO_SIZEOF(struct in_addr*);
 			saw_xdigit = 0;
@@ -216,12 +368,14 @@ static int str_to_ipv6 (const mio_ooch_t* src, mio_oow_t len, struct in6_addr* i
 }
 #endif
 
-int mio_oocharstoskad (mio_t* mio, const mio_ooch_t* str, mio_oow_t len, mio_skad_t* _skad)
+/* ---------------------------------------------------------- */
+
+int mio_ucharstoskad (mio_t* mio, const mio_uch_t* str, mio_oow_t len, mio_skad_t* _skad)
 {
 	mio_skad_alt_t* skad = (mio_skad_alt_t*)_skad;
-	const mio_ooch_t* p;
-	const mio_ooch_t* end;
-	mio_oocs_t tmp;
+	const mio_uch_t* p;
+	const mio_uch_t* end;
+	mio_ucs_t tmp;
 
 	p = str;
 	end = str + len;
@@ -237,14 +391,10 @@ int mio_oocharstoskad (mio_t* mio, const mio_ooch_t* str, mio_oow_t len, mio_ska
 #if defined(AF_UNIX)
 	if (*p == '/' && len >= 2)
 	{
-	#if defined(MIO_OOCH_IS_BCH)
-		mio_copy_bcstr (skad->un.sun_path, MIO_COUNTOF(skad->un.sun_path), str);
-	#else
 		mio_oow_t dstlen;
 		dstlen = MIO_COUNTOF(skad->un.sun_path) - 1;
 		if (mio_convutobchars(mio, p, &len, skad->un.sun_path, &dstlen) <= -1) return -1;
 		skad->un.sun_path[dstlen] = '\0';
-	#endif
 		skad->un.sun_family = AF_UNIX;
 		return 0;
 	}
@@ -254,7 +404,7 @@ int mio_oocharstoskad (mio_t* mio, const mio_ooch_t* str, mio_oow_t len, mio_ska
 	if (*p == '[')
 	{
 		/* IPv6 address */
-		tmp.ptr = (mio_ooch_t*)++p; /* skip [ and remember the position */
+		tmp.ptr = (mio_uch_t*)++p; /* skip [ and remember the position */
 		while (p < end && *p != '%' && *p != ']') p++;
 
 		if (p >= end) goto no_rbrack;
@@ -294,7 +444,7 @@ int mio_oocharstoskad (mio_t* mio, const mio_ooch_t* str, mio_oow_t len, mio_ska
 			else
 			{
 				/* interface name as a scope id? */
-				const mio_ooch_t* stmp = p;
+				const mio_uch_t* stmp = p;
 				unsigned int index;
 				do p++; while (p < end && *p != ']');
 				if (mio_ucharstoifindex(mio, stmp, p - stmp, &index) <= -1) return -1;
@@ -305,18 +455,18 @@ int mio_oocharstoskad (mio_t* mio, const mio_ooch_t* str, mio_oow_t len, mio_ska
 		}
 		p++; /* skip ] */
 
-		if (str_to_ipv6(tmp.ptr, tmp.len, &skad->in6.sin6_addr) <= -1) goto unrecog;
+		if (uchars_to_ipv6(tmp.ptr, tmp.len, &skad->in6.sin6_addr) <= -1) goto unrecog;
 		skad->in6.sin6_family = AF_INET6;
 	}
 	else
 	{
 #endif
 		/* IPv4 address */
-		tmp.ptr = (mio_ooch_t*)p;
+		tmp.ptr = (mio_uch_t*)p;
 		while (p < end && *p != ':') p++;
 		tmp.len = p - tmp.ptr;
 
-		if (str_to_ipv4(tmp.ptr, tmp.len, &skad->in4.sin_addr) <= -1)
+		if (uchars_to_ipv4(tmp.ptr, tmp.len, &skad->in4.sin_addr) <= -1)
 		{
 		#if (MIO_SIZEOF_STRUCT_SOCKADDR_IN6 > 0)
 			/* check if it is an IPv6 address not enclosed in []. 
@@ -327,11 +477,10 @@ int mio_oocharstoskad (mio_t* mio, const mio_ooch_t* str, mio_oow_t len, mio_ska
 				goto unrecog;
 			}
 
-
 			while (p < end && *p != '%') p++;
 			tmp.len = p - tmp.ptr;
 
-			if (str_to_ipv6(tmp.ptr, tmp.len, &skad->in6.sin6_addr) <= -1) goto unrecog;
+			if (uchars_to_ipv6(tmp.ptr, tmp.len, &skad->in6.sin6_addr) <= -1) goto unrecog;
 
 			if (p < end && *p == '%')
 			{
@@ -367,7 +516,7 @@ int mio_oocharstoskad (mio_t* mio, const mio_ooch_t* str, mio_oow_t len, mio_ska
 				else
 				{
 					/* interface name as a scope id? */
-					const mio_ooch_t* stmp = p;
+					const mio_uch_t* stmp = p;
 					unsigned int index;
 					do p++; while (p < end);
 					if (mio_ucharstoifindex(mio, stmp, p - stmp, &index) <= -1) return -1;
@@ -396,7 +545,218 @@ int mio_oocharstoskad (mio_t* mio, const mio_ooch_t* str, mio_oow_t len, mio_ska
 
 		p++; /* skip : */
 
-		tmp.ptr = (mio_ooch_t*)p;
+		tmp.ptr = (mio_uch_t*)p;
+		while (p < end && *p >= '0' && *p <= '9')
+		{
+			port = port * 10 + (*p - '0');
+			p++;
+		}
+
+		tmp.len = p - tmp.ptr;
+		if (tmp.len <= 0 || tmp.len >= 6 || 
+		    port > MIO_TYPE_MAX(mio_uint16_t)) 
+		{
+			mio_seterrbfmt (mio, MIO_EINVAL, "port number blank or too large");
+			return -1;
+		}
+
+	#if (MIO_SIZEOF_STRUCT_SOCKADDR_IN6 > 0)
+		if (skad->in4.sin_family == AF_INET)
+			skad->in4.sin_port = mio_hton16(port);
+		else
+			skad->in6.sin6_port = mio_hton16(port);
+	#else
+		skad->in4.sin_port = mio_hton16(port);
+	#endif
+	}
+
+	return 0;
+
+unrecog:
+	mio_seterrbfmt (mio, MIO_EINVAL, "unrecognized address");
+	return -1;
+	
+no_rbrack:
+	mio_seterrbfmt (mio, MIO_EINVAL, "missing right bracket");
+	return -1;
+}
+
+/* ---------------------------------------------------------- */
+
+int mio_bcharstoskad (mio_t* mio, const mio_bch_t* str, mio_oow_t len, mio_skad_t* _skad)
+{
+	mio_skad_alt_t* skad = (mio_skad_alt_t*)_skad;
+	const mio_bch_t* p;
+	const mio_bch_t* end;
+	mio_bcs_t tmp;
+
+	p = str;
+	end = str + len;
+
+	if (p >= end) 
+	{
+		mio_seterrbfmt (mio, MIO_EINVAL, "blank address");
+		return -1;
+	}
+
+	MIO_MEMSET (skad, 0, MIO_SIZEOF(*skad));
+
+#if defined(AF_UNIX)
+	if (*p == '/' && len >= 2)
+	{
+		mio_copy_bcstr (skad->un.sun_path, MIO_COUNTOF(skad->un.sun_path), str);
+		skad->un.sun_family = AF_UNIX;
+		return 0;
+	}
+#endif
+
+#if (MIO_SIZEOF_STRUCT_SOCKADDR_IN6 > 0)
+	if (*p == '[')
+	{
+		/* IPv6 address */
+		tmp.ptr = (mio_bch_t*)++p; /* skip [ and remember the position */
+		while (p < end && *p != '%' && *p != ']') p++;
+
+		if (p >= end) goto no_rbrack;
+
+		tmp.len = p - tmp.ptr;
+		if (*p == '%')
+		{
+			/* handle scope id */
+			mio_uint32_t x;
+
+			p++; /* skip % */
+
+			if (p >= end)
+			{
+				/* premature end */
+				mio_seterrbfmt (mio, MIO_EINVAL, "scope id blank");
+				return -1;
+			}
+
+			if (*p >= '0' && *p <= '9') 
+			{
+				/* numeric scope id */
+				skad->in6.sin6_scope_id = 0;
+				do
+				{
+					x = skad->in6.sin6_scope_id * 10 + (*p - '0');
+					if (x < skad->in6.sin6_scope_id) 
+					{
+						mio_seterrbfmt (mio, MIO_EINVAL, "scope id too large");
+						return -1; /* overflow */
+					}
+					skad->in6.sin6_scope_id = x;
+					p++;
+				}
+				while (p < end && *p >= '0' && *p <= '9');
+			}
+			else
+			{
+				/* interface name as a scope id? */
+				const mio_bch_t* stmp = p;
+				unsigned int index;
+				do p++; while (p < end && *p != ']');
+				if (mio_bcharstoifindex(mio, stmp, p - stmp, &index) <= -1) return -1;
+				skad->in6.sin6_scope_id = index;
+			}
+
+			if (p >= end || *p != ']') goto no_rbrack;
+		}
+		p++; /* skip ] */
+
+		if (bchars_to_ipv6(tmp.ptr, tmp.len, &skad->in6.sin6_addr) <= -1) goto unrecog;
+		skad->in6.sin6_family = AF_INET6;
+	}
+	else
+	{
+#endif
+		/* IPv4 address */
+		tmp.ptr = (mio_bch_t*)p;
+		while (p < end && *p != ':') p++;
+		tmp.len = p - tmp.ptr;
+
+		if (bchars_to_ipv4(tmp.ptr, tmp.len, &skad->in4.sin_addr) <= -1)
+		{
+		#if (MIO_SIZEOF_STRUCT_SOCKADDR_IN6 > 0)
+			/* check if it is an IPv6 address not enclosed in []. 
+			 * the port number can't be specified in this format. */
+			if (p >= end || *p != ':') 
+			{
+				/* without :, it can't be an ipv6 address */
+				goto unrecog;
+			}
+
+
+			while (p < end && *p != '%') p++;
+			tmp.len = p - tmp.ptr;
+
+			if (bchars_to_ipv6(tmp.ptr, tmp.len, &skad->in6.sin6_addr) <= -1) goto unrecog;
+
+			if (p < end && *p == '%')
+			{
+				/* handle scope id */
+				mio_uint32_t x;
+
+				p++; /* skip % */
+
+				if (p >= end)
+				{
+					/* premature end */
+					mio_seterrbfmt (mio, MIO_EINVAL, "scope id blank");
+					return -1;
+				}
+
+				if (*p >= '0' && *p <= '9') 
+				{
+					/* numeric scope id */
+					skad->in6.sin6_scope_id = 0;
+					do
+					{
+						x = skad->in6.sin6_scope_id * 10 + (*p - '0');
+						if (x < skad->in6.sin6_scope_id) 
+						{
+							mio_seterrbfmt (mio, MIO_EINVAL, "scope id too large");
+							return -1; /* overflow */
+						}
+						skad->in6.sin6_scope_id = x;
+						p++;
+					}
+					while (p < end && *p >= '0' && *p <= '9');
+				}
+				else
+				{
+					/* interface name as a scope id? */
+					const mio_bch_t* stmp = p;
+					unsigned int index;
+					do p++; while (p < end);
+					if (mio_bcharstoifindex(mio, stmp, p - stmp, &index) <= -1) return -1;
+					skad->in6.sin6_scope_id = index;
+				}
+			}
+
+			if (p < end) goto unrecog; /* some gargage after the end? */
+
+			skad->in6.sin6_family = AF_INET6;
+			return 0;
+		#else
+			goto unrecog;
+		#endif
+		}
+
+		skad->in4.sin_family = AF_INET;
+#if (MIO_SIZEOF_STRUCT_SOCKADDR_IN6 > 0)
+	}
+#endif
+
+	if (p < end && *p == ':') 
+	{
+		/* port number */
+		mio_uint32_t port = 0;
+
+		p++; /* skip : */
+
+		tmp.ptr = (mio_bch_t*)p;
 		while (p < end && *p >= '0' && *p <= '9')
 		{
 			port = port * 10 + (*p - '0');