From 3ff8866dec556e4324cee3bfd2b1362cc53acb4c Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Tue, 24 Dec 2019 16:13:19 +0000 Subject: [PATCH] experimental socket address conversion function --- hawk/lib/err.c | 93 +++++++++- hawk/lib/hawk-cmn.h | 10 - hawk/lib/hawk-utl.h | 37 ++++ hawk/lib/utl-skad.c | 442 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 571 insertions(+), 11 deletions(-) create mode 100644 hawk/lib/utl-skad.c diff --git a/hawk/lib/err.c b/hawk/lib/err.c index 5dce0e42..ecbb261e 100644 --- a/hawk/lib/err.c +++ b/hawk/lib/err.c @@ -486,7 +486,7 @@ static int rtx_err_uchars (hawk_fmtout_t* fmtout, const hawk_uch_t* ptr, hawk_oo rtx->errmsg_len += len; #else if (max <= 0) return 1; - hawk_conv_uchars_to_bchars_with_cmgr (ptr, &len, &rtx->_gem.errmsg[rtx->errmsg_len], &max, hawk_getcmgr(hawk)); + hawk_conv_uchars_to_bchars_with_cmgr (ptr, &len, &rtx->_gem.errmsg[rtx->errmsg_len], &max, hawk_rtx_getcmgr(rtx)); rtx->errmsg_len += max; #endif rtx->_gem.errmsg[rtx->errmsg_len] = '\0'; @@ -572,3 +572,94 @@ void hawk_gem_seterrnum (hawk_gem_t* gem, const hawk_loc_t* errloc, hawk_errnum_ gem->errmsg[0] = '\0'; gem->errloc = (errloc? *errloc: _nullloc); } + + +static int gem_err_bchars (hawk_fmtout_t* fmtout, const hawk_bch_t* ptr, hawk_oow_t len) +{ + hawk_gem_t* gem = (hawk_gem_t*)fmtout->ctx; + hawk_oow_t max; + + max = HAWK_COUNTOF(gem->errmsg) - gem->errmsg_len - 1; + +#if defined(HAWK_OOCH_IS_UCH) + if (max <= 0) return 1; + hawk_conv_bchars_to_uchars_with_cmgr (ptr, &len, &gem->errmsg[gem->errmsg_len], &max, gem->cmgr, 1); + gem->errmsg_len += max; +#else + if (len > max) len = max; + if (len <= 0) return 1; + HAWK_MEMCPY (&gem->errinf.msg[gem->errmsg_len], ptr, len * HAWK_SIZEOF(*ptr)); + gem->errmsg_len += len; +#endif + + gem->errmsg[gem->errmsg_len] = '\0'; + + return 1; /* success */ +} + +static int gem_err_uchars (hawk_fmtout_t* fmtout, const hawk_uch_t* ptr, hawk_oow_t len) +{ + hawk_gem_t* gem = (hawk_gem_t*)fmtout->ctx; + hawk_oow_t max; + + max = HAWK_COUNTOF(gem->errmsg) - gem->errmsg_len - 1; + +#if defined(HAWK_OOCH_IS_UCH) + if (len > max) len = max; + if (len <= 0) return 1; + HAWK_MEMCPY (&gem->errmsg[gem->errmsg_len], ptr, len * HAWK_SIZEOF(*ptr)); + gem->errmsg_len += len; +#else + if (max <= 0) return 1; + hawk_conv_uchars_to_bchars_with_cmgr (ptr, &len, &gem->errmsg[gem->errmsg_len], &max, gem->cmgr); + gem->errmsg_len += max; +#endif + gem->errmsg[gem->errmsg_len] = '\0'; + return 1; /* success */ +} + +void hawk_gem_seterrbfmt (hawk_gem_t* gem, const hawk_loc_t* errloc, hawk_errnum_t errnum, const hawk_bch_t* errfmt, ...) +{ + va_list ap; + hawk_fmtout_t fo; + + /*if (hawk->shuterr) return;*/ + gem->errmsg_len = 0; + gem->errmsg[0] = '\0'; + + HAWK_MEMSET (&fo, 0, HAWK_SIZEOF(fo)); + fo.mmgr = hawk_gem_getmmgr(gem); + fo.putbchars = gem_err_bchars; + fo.putuchars = gem_err_uchars; + fo.ctx = gem; + + va_start (ap, errfmt); + hawk_bfmt_outv (&fo, errfmt, ap); + va_end (ap); + + gem->errnum = errnum; + gem->errloc = (errloc? *errloc: _nullloc); +} + +void hawk_gem_seterrufmt (hawk_gem_t* gem, const hawk_loc_t* errloc, hawk_errnum_t errnum, const hawk_uch_t* errfmt, ...) +{ + va_list ap; + hawk_fmtout_t fo; + + /*if (hawk->shuterr) return;*/ + gem->errmsg_len = 0; + gem->errmsg[0] = '\0'; + + HAWK_MEMSET (&fo, 0, HAWK_SIZEOF(fo)); + fo.mmgr = hawk_gem_getmmgr(gem); + fo.putbchars = gem_err_bchars; + fo.putuchars = gem_err_uchars; + fo.ctx = gem; + + va_start (ap, errfmt); + hawk_ufmt_outv (&fo, errfmt, ap); + va_end (ap); + + gem->errnum = errnum; + gem->errloc = (errloc? *errloc: _nullloc); +} diff --git a/hawk/lib/hawk-cmn.h b/hawk/lib/hawk-cmn.h index 589004c6..a4bcf287 100644 --- a/hawk/lib/hawk-cmn.h +++ b/hawk/lib/hawk-cmn.h @@ -927,13 +927,6 @@ struct hawk_loc_t }; typedef struct hawk_loc_t hawk_loc_t; -typedef void (*hawk_assertfail_t) ( - hawk_gem_t* gem, - const hawk_bch_t* expr, - const hawk_bch_t* file, - hawk_oow_t line -); - struct hawk_gem_t { hawk_mmgr_t* mmgr; @@ -941,9 +934,6 @@ struct hawk_gem_t hawk_errnum_t errnum; hawk_ooch_t errmsg[HAWK_ERRMSG_CAPA]; hawk_loc_t errloc; -#if defined(HAWK_BUILD_DEBUG) - hawk_assertfail_t assertfail; -#endif }; enum hawk_log_mask_t diff --git a/hawk/lib/hawk-utl.h b/hawk/lib/hawk-utl.h index 3d204d5c..4f5a2b02 100644 --- a/hawk/lib/hawk-utl.h +++ b/hawk/lib/hawk-utl.h @@ -354,6 +354,33 @@ typedef int (*hawk_sort_comperx_t) ( ); +/* ========================================================================= + * SOCKET ADDRESS + * ========================================================================= */ +#define HAWK_SIZEOF_SKAD_T 1 +#if (HAWK_SIZEOF_STRUCT_SOCKADDR_IN > HAWK_SIZEOF_SKAD_T) +# undef HAWK_SIZEOF_SKAD_T +# define HAWK_SIZEOF_SKAD_T HAWK_SIZEOF_STRUCT_SOCKADDR_IN +#endif +#if (HAWK_SIZEOF_STRUCT_SOCKADDR_IN6 > 0) +# undef HAWK_SIZEOF_SKAD_T +# define HAWK_SIZEOF_SKAD_T HAWK_SIZEOF_STRUCT_SOCKADDR_IN6 +#endif +#if (HAWK_SIZEOF_STRUCT_SOCKADDR_LL > 0) +# undef HAWK_SIZEOF_SKAD_T +# define HAWK_SIZEOF_SKAD_T HAWK_SIZEOF_STRUCT_SOCKADDR_LL +#endif +#if (HAWK_SIZEOF_STRUCT_SOCKADDR_UN > 0) +# undef HAWK_SIZEOF_SKAD_T +# define HAWK_SIZEOF_SKAD_T HAWK_SIZEOF_STRUCT_SOCKADDR_UN +#endif + +struct hawk_skad_t +{ + hawk_uint8_t data[HAWK_SIZEOF_SKAD_T]; +}; +typedef struct hawk_skad_t hawk_skad_t; + #if defined(__cplusplus) extern "C" { #endif @@ -1542,6 +1569,16 @@ HAWK_EXPORT void hawk_sub_time ( ); +/* ========================================================================= + * SOCKET ADDRESS + * ========================================================================= */ +HAWK_EXPORT int hawk_oochars_to_skad ( + hawk_t* hawk, + const hawk_ooch_t* str, + hawk_oow_t len, + hawk_skad_t* skad +); + /* ========================================================================= * ASSERTION * ========================================================================= */ diff --git a/hawk/lib/utl-skad.c b/hawk/lib/utl-skad.c new file mode 100644 index 00000000..a6ea3969 --- /dev/null +++ b/hawk/lib/utl-skad.c @@ -0,0 +1,442 @@ +/* + * $Id$ + * + Copyright (c) 2006-2019 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 WARRANTIES + 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 +#include "hawk-prv.h" + +#include +#include +#if defined(HAVE_NETINET_IN_H) +# include +#endif +#if defined(HAVE_SYS_UN_H) +# include +#endif +#if defined(HAVE_NETPACKET_PACKET_H) +# include +#endif +#if defined(HAVE_NET_IF_DL_H) +# include +#endif + +union hawk_skad_alt_t +{ + struct sockaddr sa; +#if (HAWK_SIZEOF_STRUCT_SOCKADDR_IN > 0) + struct sockaddr_in in4; +#endif +#if (HAWK_SIZEOF_STRUCT_SOCKADDR_IN6 > 0) + struct sockaddr_in6 in6; +#endif +#if (HAWK_SIZEOF_STRUCT_SOCKADDR_LL > 0) + struct sockaddr_ll ll; +#endif +#if (HAWK_SIZEOF_STRUCT_SOCKADDR_UN > 0) + struct sockaddr_un un; +#endif +}; +typedef union hawk_skad_alt_t hawk_skad_alt_t; + +static int str_to_ipv4 (const hawk_ooch_t* str, hawk_oow_t len, struct in_addr* inaddr) +{ + const hawk_ooch_t* end; + int dots = 0, digits = 0; + hawk_uint32_t acc = 0, addr = 0; + hawk_ooch_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 = hawk_hton32(addr); + return 0; + +} + +#if (HAWK_SIZEOF_STRUCT_SOCKADDR_IN6 > 0) +static int str_to_ipv6 (const hawk_ooch_t* src, hawk_oow_t len, struct in6_addr* inaddr) +{ + hawk_uint8_t* tp, * endp, * colonp; + const hawk_ooch_t* curtok; + hawk_ooch_t ch; + int saw_xdigit; + unsigned int val; + const hawk_ooch_t* src_end; + + src_end = src + len; + + HAWK_MEMSET (inaddr, 0, HAWK_SIZEOF(*inaddr)); + tp = &inaddr->s6_addr[0]; + endp = &inaddr->s6_addr[HAWK_COUNTOF(inaddr->s6_addr)]; + colonp = HAWK_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++ = (hawk_uint8_t)(val >> 8) & 0xff; + *tp++ = (hawk_uint8_t)val & 0xff; + saw_xdigit = 0; + val = 0; + continue; + } + + if (ch == '.' && ((tp + HAWK_SIZEOF(struct in_addr)) <= endp) && + str_to_ipv4(curtok, src_end - curtok, (struct in_addr*)tp) == 0) + { + tp += HAWK_SIZEOF(struct in_addr*); + saw_xdigit = 0; + break; + } + + return -1; + } + + if (saw_xdigit) + { + if (tp + HAWK_SIZEOF(hawk_uint16_t) > endp) return -1; + *tp++ = (hawk_uint8_t)(val >> 8) & 0xff; + *tp++ = (hawk_uint8_t)val & 0xff; + } + if (colonp != HAWK_NULL) + { + /* + * Since some memmove()'s erroneously fail to handle + * overlapping regions, we'll do the shift by hand. + */ + hawk_oow_t n = tp - colonp; + hawk_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; +} +#endif + +int hawk_oochars_to_skad (hawk_t* hawk, const hawk_ooch_t* str, hawk_oow_t len, hawk_skad_t* _skad) +{ + hawk_skad_alt_t* skad = (hawk_skad_alt_t*)_skad; + const hawk_ooch_t* p; + const hawk_ooch_t* end; + hawk_oocs_t tmp; + + p = str; + end = str + len; + + if (p >= end) + { + hawk_seterrbfmt (hawk, HAWK_EINVAL, "blank address"); + return -1; + } + + HAWK_MEMSET (skad, 0, HAWK_SIZEOF(*skad)); + +#if defined(AF_UNIX) + if (*p == '/' && len >= 2) + { + #if defined(HAWK_OOCH_IS_BCH) + hawk_copy_bcstr (skad->un.sun_path, HAWK_COUNTOF(skad->un.sun_path), str); + #else + hawk_oow_t dstlen; + + dstlen = HAWK_COUNTOF(skad->un.sun_path) - 1; + if (hawk_convutobchars(hawk, p, &len, skad->un.sun_path, &dstlen) <= -1) + { + hawk_seterrbfmt (hawk, HAWK_EINVAL, "unable to convert encoding"); + return -1; + } + skad->un.sun_path[dstlen] = '\0'; + #endif + skad->un.sun_family = AF_UNIX; + return 0; + } +#endif + +#if (HAWK_SIZEOF_STRUCT_SOCKADDR_IN6 > 0) + if (*p == '[') + { + /* IPv6 address */ + tmp.ptr = (hawk_ooch_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 */ + hawk_uint32_t x; + + p++; /* skip % */ + + if (p >= end) + { + /* premature end */ + hawk_seterrbfmt (hawk, HAWK_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) + { + hawk_seterrbfmt (hawk, HAWK_EINVAL, "scope id too large"); + return -1; /* overflow */ + } + skad->in6.sin6_scope_id = x; + p++; + } + while (p < end && *p >= '0' && *p <= '9'); + } + else + { +#if 0 +TODO: + /* interface name as a scope id? */ + const hawk_ooch_t* stmp = p; + unsigned int index; + do p++; while (p < end && *p != ']'); + if (hawk_nwifwcsntoindex(stmp, p - stmp, &index) <= -1) return -1; + tmpad.u.in6.scope = index; +#endif + } + + if (p >= end || *p != ']') goto no_rbrack; + } + p++; /* skip ] */ + + if (str_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 = (hawk_ooch_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 (HAWK_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 (str_to_ipv6(tmp.ptr, tmp.len, &skad->in6.sin6_addr) <= -1) goto unrecog; + + if (p < end && *p == '%') + { + /* handle scope id */ + hawk_uint32_t x; + + p++; /* skip % */ + + if (p >= end) + { + /* premature end */ + hawk_seterrbfmt (hawk, HAWK_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) + { + hawk_seterrbfmt (hawk, HAWK_EINVAL, "scope id too large"); + return -1; /* overflow */ + } + skad->in6.sin6_scope_id = x; + p++; + } + while (p < end && *p >= '0' && *p <= '9'); + } + else + { +#if 0 +TODO + /* interface name as a scope id? */ + const hawk_ooch_t* stmp = p; + unsigned int index; + do p++; while (p < end); + if (hawk_nwifwcsntoindex (stmp, p - stmp, &index) <= -1) return -1; + skad->in6.sin6_scope_id = index; +#endif + } + } + + 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 (HAWK_SIZEOF_STRUCT_SOCKADDR_IN6 > 0) + } +#endif + + if (p < end && *p == ':') + { + /* port number */ + hawk_uint32_t port = 0; + + p++; /* skip : */ + + tmp.ptr = (hawk_ooch_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 > HAWK_TYPE_MAX(hawk_uint16_t)) + { + hawk_seterrbfmt (hawk, HAWK_EINVAL, "port number blank or too large"); + return -1; + } + + #if (HAWK_SIZEOF_STRUCT_SOCKADDR_IN6 > 0) + if (skad->in4.sin_family == AF_INET) + skad->in4.sin_port = hawk_hton16(port); + else + skad->in6.sin6_port = hawk_hton16(port); + #else + skad->in4.sin_port = hawk_hton16(port); + #endif + } + + return 0; + +unrecog: + hawk_seterrbfmt (hawk, HAWK_EINVAL, "unrecognized address"); + return -1; + +no_rbrack: + hawk_seterrbfmt (hawk, HAWK_EINVAL, "missing right bracket"); + return -1; +}