From 4666b5efff6803296d671519659255de875eb85d Mon Sep 17 00:00:00 2001 From: "hyunghwan.chung" Date: Wed, 10 Jan 2018 14:32:21 +0000 Subject: [PATCH] added partital socket address conversion routines to sck-addr.c --- moo/kernel/Socket.moo | 4 +- moo/lib/utl.c | 79 ++++++++- moo/mod/sck-addr.c | 394 ++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 460 insertions(+), 17 deletions(-) diff --git a/moo/kernel/Socket.moo b/moo/kernel/Socket.moo index 32d7176..608724f 100644 --- a/moo/kernel/Socket.moo +++ b/moo/kernel/Socket.moo @@ -378,9 +378,7 @@ class MyObject(Object) method(#class) main { | s conact inact outact | - - -SocketAddress new dump. +(SocketAddress fromString: '192.168.123.232:99') dump. '****************************' dump. (* diff --git a/moo/lib/utl.c b/moo/lib/utl.c index 6a9a759..946e640 100644 --- a/moo/lib/utl.c +++ b/moo/lib/utl.c @@ -736,7 +736,7 @@ int moo_convbtouchars (moo_t* moo, const moo_bch_t* bcs, moo_oow_t* bcslen, moo_ if (n <= -1) { /* -1: illegal character, -2: buffer too small, -3: incomplete sequence */ - moo->errnum = (n == -2)? MOO_EBUFFULL: MOO_EECERR; + moo_seterrnum (moo, (n == -2)? MOO_EBUFFULL: MOO_EECERR); } return n; @@ -751,7 +751,7 @@ int moo_convutobchars (moo_t* moo, const moo_uch_t* ucs, moo_oow_t* ucslen, moo_ if (n <= -1) { - moo->errnum = (n == -2)? MOO_EBUFFULL: MOO_EECERR; + moo_seterrnum (moo, (n == -2)? MOO_EBUFFULL: MOO_EECERR); } return n; @@ -766,7 +766,7 @@ int moo_convbtoucstr (moo_t* moo, const moo_bch_t* bcs, moo_oow_t* bcslen, moo_u if (n <= -1) { - moo->errnum = (n == -2)? MOO_EBUFFULL: MOO_EECERR; + moo_seterrnum (moo, (n == -2)? MOO_EBUFFULL: MOO_EECERR); } return n; @@ -781,7 +781,7 @@ int moo_convutobcstr (moo_t* moo, const moo_uch_t* ucs, moo_oow_t* ucslen, moo_b if (n <= -1) { - moo->errnum = (n == -2)? MOO_EBUFFULL: MOO_EECERR; + moo_seterrnum (moo, (n == -2)? MOO_EBUFFULL: MOO_EECERR); } return n; @@ -931,3 +931,74 @@ moo_bch_t* moo_dupbchars (moo_t* moo, const moo_bch_t* bcs, moo_oow_t bcslen) return ptr; } +/* ----------------------------------------------------------------------- */ + + +#if defined(MOO_HAVE_UINT16_T) + +moo_uint16_t moo_ntoh16 (moo_uint16_t x) +{ +#if defined(MOO_ENDIAN_BIG) + return x; +#elif defined(MOO_ENDIAN_LITTLE) + moo_uint8_t* c = (moo_uint8_t*)&x; + return (moo_uint16_t)( + ((moo_uint16_t)c[0] << 8) | + ((moo_uint16_t)c[1] << 0)); +#else +# error Unknown endian +#endif +} + +moo_uint16_t moo_hton16 (moo_uint16_t x) +{ +#if defined(MOO_ENDIAN_BIG) + return x; +#elif defined(MOO_ENDIAN_LITTLE) + moo_uint8_t* c = (moo_uint8_t*)&x; + return (moo_uint16_t)( + ((moo_uint16_t)c[0] << 8) | + ((moo_uint16_t)c[1] << 0)); +#else +# error Unknown endian +#endif +} + +#endif + +/* --------------------------------------------------------------- */ + +#if defined(MOO_HAVE_UINT32_T) + +moo_uint32_t moo_ntoh32 (moo_uint32_t x) +{ +#if defined(MOO_ENDIAN_BIG) + return x; +#elif defined(MOO_ENDIAN_LITTLE) + moo_uint8_t* c = (moo_uint8_t*)&x; + return (moo_uint32_t)( + ((moo_uint32_t)c[0] << 24) | + ((moo_uint32_t)c[1] << 16) | + ((moo_uint32_t)c[2] << 8) | + ((moo_uint32_t)c[3] << 0)); +#else +# error Unknown endian +#endif +} + +moo_uint32_t moo_hton32 (moo_uint32_t x) +{ +#if defined(MOO_ENDIAN_BIG) + return x; +#elif defined(MOO_ENDIAN_LITTLE) + moo_uint8_t* c = (moo_uint8_t*)&x; + return (moo_uint32_t)( + ((moo_uint32_t)c[0] << 24) | + ((moo_uint32_t)c[1] << 16) | + ((moo_uint32_t)c[2] << 8) | + ((moo_uint32_t)c[3] << 0)); +#else +# error Unknown endian +#endif +} +#endif diff --git a/moo/mod/sck-addr.c b/moo/mod/sck-addr.c index f6376b9..1648f1d 100644 --- a/moo/mod/sck-addr.c +++ b/moo/mod/sck-addr.c @@ -100,20 +100,396 @@ union sockaddr_t }; typedef union sockaddr_t sockaddr_t; +static int str_to_ipv4 (const moo_ooch_t* str, moo_oow_t len, struct in_addr* inaddr) +{ + const moo_ooch_t* end; + int dots = 0, digits = 0; + moo_uint32_t acc = 0, addr = 0; + moo_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 = moo_hton32(addr); + return 0; + +} + +static int str_to_ipv6 (const moo_ooch_t* src, moo_oow_t len, struct in6_addr* inaddr) +{ + moo_uint8_t* tp, * endp, * colonp; + const moo_ooch_t* curtok; + moo_ooch_t ch; + int saw_xdigit; + unsigned int val; + const moo_ooch_t* src_end; + + src_end = src + len; + + MOO_MEMSET (inaddr, 0, MOO_SIZEOF(*inaddr)); + tp = &inaddr->s6_addr[0]; + endp = &inaddr->s6_addr[MOO_COUNTOF(inaddr->s6_addr)]; + colonp = MOO_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++ = (moo_uint8_t)(val >> 8) & 0xff; + *tp++ = (moo_uint8_t)val & 0xff; + saw_xdigit = 0; + val = 0; + continue; + } + + if (ch == '.' && ((tp + MOO_SIZEOF(struct in_addr)) <= endp) && + str_to_ipv4(curtok, src_end - curtok, (struct in_addr*)tp) == 0) + { + tp += MOO_SIZEOF(struct in_addr*); + saw_xdigit = 0; + break; + } + + return -1; + } + + if (saw_xdigit) + { + if (tp + MOO_SIZEOF(moo_uint16_t) > endp) return -1; + *tp++ = (moo_uint8_t)(val >> 8) & 0xff; + *tp++ = (moo_uint8_t)val & 0xff; + } + if (colonp != MOO_NULL) + { + /* + * Since some memmove()'s erroneously fail to handle + * overlapping regions, we'll do the shift by hand. + */ + moo_oow_t n = tp - colonp; + moo_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 str_to_sockaddr (moo_t* moo, const moo_ooch_t* str, moo_oow_t len, sockaddr_t* nwad) +{ + const moo_ooch_t* p; + const moo_ooch_t* end; + moo_oocs_t tmp; + + p = str; + end = str + len; + + if (p >= end) + { + moo_seterrbfmt (moo, MOO_EINVAL, "blank address"); + return -1; + } + + MOO_MEMSET (nwad, 0, MOO_SIZEOF(*nwad)); + +#if defined(AF_UNIX) + if (*p == '/' && len >= 2) + { + #if defined(MOO_OOCH_IS_BCH) + moo_copybcstr (nwad->un.sun_path, MOO_COUNTOF(nwad->un.sun_path), str); + #else + moo_oow_t dstlen; + + dstlen = MOO_COUNTOF(nwad->un.sun_path) - 1; + if (moo_convutobchars (moo, p, &len, nwad->un.sun_path, &dstlen) <= -1) + { + moo_seterrbfmt (moo, MOO_EINVAL, "unable to convert encoding"); + return -1; + } + nwad->un.sun_path[dstlen] = '\0'; + #endif + nwad->un.sun_family = AF_UNIX; + return 0; + } +#endif + + if (*p == '[') + { + /* IPv6 address */ + tmp.ptr = (moo_ooch_t*)++p; /* skip [ and remember the position */ + while (p < end && *p != '%' && *p != ']') p++; + + if (p >= end) goto norbrack; + + tmp.len = p - tmp.ptr; + if (*p == '%') + { + /* handle scope id */ + moo_uint32_t x; + + p++; /* skip % */ + + if (p >= end) + { + /* premature end */ + moo_seterrbfmt (moo, MOO_EINVAL, "scope id blank"); + return -1; + } + + if (*p >= '0' && *p <= '9') + { + /* numeric scope id */ + nwad->in6.sin6_scope_id = 0; + do + { + x = nwad->in6.sin6_scope_id * 10 + (*p - '0'); + if (x < nwad->in6.sin6_scope_id) + { + moo_seterrbfmt (moo, MOO_EINVAL, "scope id too large"); + return -1; /* overflow */ + } + nwad->in6.sin6_scope_id = x; + p++; + } + while (p < end && *p >= '0' && *p <= '9'); + } + else + { +#if 0 +TODO: + /* interface name as a scope id? */ + const moo_ooch_t* stmp = p; + unsigned int index; + do p++; while (p < end && *p != ']'); + if (moo_nwifwcsntoindex (stmp, p - stmp, &index) <= -1) return -1; + tmpad.u.in6.scope = index; +#endif + } + + if (p >= end || *p != ']') goto norbrack; + } + p++; /* skip ] */ + + if (str_to_ipv6(tmp.ptr, tmp.len, &nwad->in6.sin6_addr) <= -1) goto unrecog; + nwad->in6.sin6_family = AF_INET6; + } + else + { + /* IPv4 address */ + tmp.ptr = (moo_ooch_t*)p; + while (p < end && *p != ':') p++; + tmp.len = p - tmp.ptr; + + if (str_to_ipv4(tmp.ptr, tmp.len, &nwad->in4.sin_addr) <= -1) + { + /* 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, &nwad->in6.sin6_addr) <= -1) goto unrecog; + + if (p < end && *p == '%') + { + /* handle scope id */ + moo_uint32_t x; + + p++; /* skip % */ + + if (p >= end) + { + /* premature end */ + moo_seterrbfmt (moo, MOO_EINVAL, "scope id blank"); + return -1; + } + + if (*p >= '0' && *p <= '9') + { + /* numeric scope id */ + nwad->in6.sin6_scope_id = 0; + do + { + x = nwad->in6.sin6_scope_id * 10 + (*p - '0'); + if (x < nwad->in6.sin6_scope_id) + { + moo_seterrbfmt (moo, MOO_EINVAL, "scope id too large"); + return -1; /* overflow */ + } + nwad->in6.sin6_scope_id= x; + p++; + } + while (p < end && *p >= '0' && *p <= '9'); + } + else + { +#if 0 +TODO + /* interface name as a scope id? */ + const moo_ooch_t* stmp = p; + unsigned int index; + do p++; while (p < end); + if (moo_nwifwcsntoindex (stmp, p - stmp, &index) <= -1) return -1; + nwad->in6.sin6_scope_id = index; +#endif + } + } + + if (p < end) goto unrecog; /* some gargage after the end? */ + + nwad->in6.sin6_family = AF_INET6; + return 0; + } + + nwad->in4.sin_family = AF_INET; + } + + if (p < end && *p == ':') + { + /* port number */ + moo_uint32_t port = 0; + + p++; /* skip : */ + + tmp.ptr = (moo_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 > MOO_TYPE_MAX(moo_uint16_t)) + { + moo_seterrbfmt (moo, MOO_EINVAL, "port number blank or too large"); + return -1; + } + + if (nwad->in4.sin_family == AF_INET) + nwad->in4.sin_port = moo_hton16(port); + else + nwad->in6.sin6_port = moo_hton16(port); + } + + return 0; + + +unrecog: + moo_seterrbfmt (moo, MOO_EINVAL, "unrecognized address"); + return -1; + +norbrack: + moo_seterrbfmt (moo, MOO_EINVAL, "missing right bracket"); + return -1; +} + + static moo_pfrc_t pf_from_string (moo_t* moo, moo_ooi_t nargs) { moo_oop_t rcv; - sck_addr_trailer_t* tr; + moo_oop_t str; rcv = (moo_oop_t)MOO_STACK_GETRCV(moo, nargs); + str = (moo_oop_t)MOO_STACK_GETARG(moo, nargs, 0); - tr = moo_getobjtrailer (moo, MOO_STACK_GETRCV(moo,nargs), MOO_NULL); - //if (tr->event) - - + MOO_PF_CHECK_RCV (moo, MOO_OBJ_IS_BYTE_POINTER(rcv) && MOO_OBJ_GET_SIZE(rcv) >= MOO_SIZEOF(sockaddr_t)); + MOO_PF_CHECK_ARGS (moo, nargs, MOO_OBJ_IS_CHAR_POINTER(str)); + + if (str_to_sockaddr (moo, MOO_OBJ_GET_CHAR_SLOT(str), MOO_OBJ_GET_SIZE(str), (sockaddr_t*)MOO_OBJ_GET_BYTE_SLOT(rcv)) <= -1) + { + return MOO_PF_FAILURE; + } + + MOO_STACK_SETRETTORCV (moo, nargs); return MOO_PF_SUCCESS; } + static moo_pfinfo_t pfinfos[] = { { I, { 'f','r','o','m','S','t','r','i','n','g',':','\0' }, 0, { pf_from_string, 1, 1 } }, @@ -121,8 +497,6 @@ static moo_pfinfo_t pfinfos[] = /* ------------------------------------------------------------------------ */ - - static int import (moo_t* moo, moo_mod_t* mod, moo_oop_class_t _class) { moo_ooi_t spec; @@ -135,9 +509,9 @@ static int import (moo_t* moo, moo_mod_t* mod, moo_oop_class_t _class) return -1; } - /* change the number of the fixed fields forcibly */ -/* TODO: check if the super class has what kind of size ... */ - + /* change the number of the fixed fields forcibly. + /* the check against the superclass is done by the main compiler + * after this import. so i perform no check about the superclass. */ spec = MOO_CLASS_SPEC_MAKE (MOO_SIZEOF(sockaddr_t), MOO_CLASS_SPEC_FLAGS(spec), MOO_CLASS_SPEC_INDEXED_TYPE(spec)); _class->spec = MOO_SMOOI_TO_OOP(spec); return 0;