aboutsummaryrefslogtreecommitdiffstats
path: root/thirdparty/apps/testapp/lb/lb.c
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/apps/testapp/lb/lb.c')
-rw-r--r--thirdparty/apps/testapp/lb/lb.c1290
1 files changed, 1290 insertions, 0 deletions
diff --git a/thirdparty/apps/testapp/lb/lb.c b/thirdparty/apps/testapp/lb/lb.c
new file mode 100644
index 0000000..058ddce
--- /dev/null
+++ b/thirdparty/apps/testapp/lb/lb.c
@@ -0,0 +1,1290 @@
+/*
+*
+* Copyright (c) 2018 Huawei Technologies Co.,Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at:
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#include "lb.h"
+
+int enable_debug = 1;
+
+#ifdef COLOR_LB_H_
+
+const static struct lb_color lb_color_list[2] = {
+ [LB_DEF_COLOR] = {
+ .clear = "\033[0m",
+ .high = "\033[1m",
+ .uline = "\033[4m",
+ .flash = "\033[5m",
+ .rev = "\033[7m",
+
+ .fblack = "\033[30m",
+ .fr__ = "\033[31m",
+ .f_g_ = "\033[32m",
+ .f__b = "\033[34m",
+ .frg_ = "\033[33m",
+ .fr_b = "\033[35m",
+ .f_gb = "\033[36m",
+ .fwhite = "\033[37m",
+
+ .bblack = "\033[40m",
+ .br__ = "\033[41m",
+ .b_g_ = "\033[42m",
+ .b__b = "\033[44m",
+ .brg_ = "\033[43m",
+ .br_b = "\033[45m",
+ .b_gb = "\033[46m",
+ .bwhite = "\033[47m",
+ },
+ [LB_NO_COLOR] = {
+ .clear = "",
+ .high = "",
+ .uline = "",
+ .flash = "",
+ .rev = "",
+
+ .fblack = "",
+ .fr__ = "",
+ .f_g_ = "",
+ .f__b = "",
+ .frg_ = "",
+ .fr_b = "",
+ .f_gb = "",
+ .fwhite = "",
+
+ .bblack = "",
+ .br__ = "",
+ .b_g_ = "",
+ .b__b = "",
+ .brg_ = "",
+ .br_b = "",
+ .b_gb = "",
+ .bwhite = "",
+ },
+};
+
+const struct lb_color *lb_color = &lb_color_list[0];
+int lb_color_index = 0;
+
+void
+lb_set_color (int index)
+{
+ lb_color_index = index;
+ lb_color = &lb_color_list[index];
+}
+
+#endif
+
+#ifdef FORMAT_LB_H_
+
+static __thread char s_fmt_buf[64][64];
+static __thread uint32_t s_fmt_id = 0;
+
+#if 0
+const char *
+f_in6 (const struct in6_addr *ip6)
+{
+ char *buf = s_fmt_buf[(s_fmt_id++) & 63];
+ char *p = buf;
+ int i;
+
+ for (i = 0; i < 8; ++i)
+ {
+ uint16_t c, v = htons (ip6->s6_addr16[i]);
+
+ c = v >> 12;
+ if (c > 9)
+ *p++ = 'A' + c - 10;
+ else if (c > 0)
+ *p++ = '0' + c;
+
+ c = (v >> 8) & 0xF;
+ if (c > 9)
+ *p++ = 'A' + c - 10;
+ else if (v > 0x00FF)
+ *p++ = '0' + c;
+
+ c = (v >> 4) & 0xF;
+ if (c > 9)
+ *p++ = 'A' + c - 10;
+ else if (v > 0x000F)
+ *p++ = '0' + c;
+
+ c = v & 0xF;
+ if (c > 9)
+ *p++ = 'A' + c - 10;
+ else
+ *p++ = '0' + c;
+
+ *p++ = ':';
+ }
+
+ p--;
+ *p = 0;
+ return buf;
+}
+#endif
+
+static int
+f_in6_f (char *buf, int len, uint16_t val)
+{
+ uint16_t v;
+ int num = 0;
+
+ if (val > 0xFFF)
+ {
+ if (num >= len)
+ return -1;
+ v = val >> 12;
+ if (v < 10)
+ buf[num++] = v + '0';
+ else
+ buf[num++] = v + 'a' - 10;
+ }
+ if (val > 0xff)
+ {
+ if (num >= len)
+ return -1;
+ v = (val >> 8) & 0xF;
+ if (v < 10)
+ buf[num++] = v + '0';
+ else
+ buf[num++] = v + 'a' - 10;
+ }
+ if (val > 0xf)
+ {
+ if (num >= len)
+ return -1;
+ v = (val >> 4) & 0xF;
+ if (v < 10)
+ buf[num++] = v + '0';
+ else
+ buf[num++] = v + 'a' - 10;
+ }
+
+ if (num >= len)
+ return -1;
+ v = val & 0xF;
+ if (v < 10)
+ buf[num++] = v + '0';
+ else
+ buf[num++] = v + 'a' - 10;
+
+ return num;
+}
+
+static void
+f_in6_z (const struct in6_addr *addr, int *pos, int *num)
+{
+ int zero_pos = 8, zero_num = 0;
+ int try_pos = -1, try_num = 0;
+ int i;
+
+ for (i = 0; i < 8; ++i)
+ {
+ if (addr->s6_addr16[i] == 0)
+ {
+ if (try_num)
+ {
+ try_num++;
+ }
+ else
+ {
+ try_pos = i;
+ try_num = 1;
+ }
+ }
+ else if (try_num)
+ {
+ if (try_num > zero_num)
+ {
+ zero_pos = try_pos;
+ zero_num = try_num;
+ }
+ try_num = 0;
+ }
+ }
+
+ if (try_num && try_num > zero_num)
+ {
+ *pos = try_pos;
+ *num = try_num;
+ }
+ else
+ {
+ *pos = zero_pos;
+ *num = zero_num;
+ }
+}
+
+int
+f_in6_s (char *buf, int size, const struct in6_addr *addr)
+{
+ int ret, i, num = 0;
+ int zero_pos, zero_num;
+
+ f_in6_z (addr, &zero_pos, &zero_num);
+
+ if (zero_pos == 0)
+ {
+ if (num >= size)
+ return -1;
+ buf[num++] = ':';
+ }
+ else
+ {
+ for (i = 0; i < zero_pos; ++i)
+ {
+ ret = f_in6_f (&buf[num], size - num, htons (addr->s6_addr16[i]));
+ if (ret < 0)
+ return -1;
+ num += ret;
+ if (num >= size)
+ return -1;
+ buf[num++] = ':';
+ }
+ if (zero_pos == 8)
+ {
+ buf[--num] = 0;
+ return num;
+ }
+ }
+
+ if (zero_pos + zero_num == 8)
+ {
+ if (num >= size)
+ return -1;
+ buf[num++] = ':';
+ }
+ else
+ {
+ for (i = zero_pos + zero_num; i < 8; ++i)
+ {
+ if (num >= size)
+ return -1;
+ buf[num++] = ':';
+ ret = f_in6_f (&buf[num], size - num, htons (addr->s6_addr16[i]));
+ if (ret < 0)
+ return -1;
+ num += ret;
+ }
+ }
+
+ if (num >= size)
+ return -1;
+ buf[num] = 0;
+
+ return num;
+}
+
+const char *
+f_in6_r (const struct in6_addr *addr, char *buf, int buflen)
+{
+ if (f_in6_s (buf, buflen, addr) <= 0)
+ return NULL;
+ return buf;
+}
+
+const char *
+f_in6 (const struct in6_addr *addr)
+{
+ char *buf = s_fmt_buf[(s_fmt_id++) & 63];
+ return f_in6_r (addr, buf, sizeof (s_fmt_buf[0]));
+}
+
+const char *
+f_inaddr (const struct sockaddr_in *addr)
+{
+ char *buf = s_fmt_buf[(s_fmt_id++) & 63];
+ char *p = buf;
+ const uint8_t *ip = (uint8_t *) & addr->sin_addr.s_addr;
+ const uint16_t pt = ntohs (addr->sin_port);
+
+#define IPP(v) do { \
+ if (v > 99) { *p++ = '0' + v / 100 % 10; } \
+ if (v > 9) { *p++ = '0' + v / 10 % 10; } \
+ *p++ = '0' + v % 10; \
+} while (0)
+
+#define PTP(v) do { \
+ if (v > 9999) { *p++ = '0' + v / 10000 % 10; } \
+ if (v > 999) { *p++ = '0' + v / 1000 % 10; } \
+ IPP(v); \
+} while (0)
+
+ IPP (ip[0]);
+ *p++ = '.';
+ IPP (ip[1]);
+ *p++ = '.';
+ IPP (ip[2]);
+ *p++ = '.';
+ IPP (ip[3]);
+ *p++ = ':';
+ PTP (pt);
+ *p = 0;
+
+ return buf;
+}
+
+const char *
+f_in6addr (const struct sockaddr_in6 *addr)
+{
+ char *p, *buf = s_fmt_buf[(s_fmt_id++) & 63];
+ const uint16_t pt = htons (addr->sin6_port);
+ int len = f_in6_s (buf, sizeof (s_fmt_buf[0]), &addr->sin6_addr);
+
+ if (len < 0)
+ return "";
+
+ p = buf + len;
+ *p++ = '.';
+ PTP (pt);
+ *p = 0;
+
+ return buf;
+}
+
+inline static int
+r_uint_use (uint64_t val)
+{
+ const static uint64_t LB_VAL[21] = {
+ 0,
+ 9,
+ 99,
+ 999,
+ 9999,
+ 99999,
+ 999999,
+ 9999999,
+ 99999999,
+ 999999999,
+ 9999999999,
+ 99999999999,
+ 999999999999,
+ 9999999999999,
+ 99999999999999,
+ 999999999999999,
+ 9999999999999999,
+ 99999999999999999,
+ 999999999999999999,
+ 9999999999999999999u,
+ 18446744073709551615u,
+ /* --%%%***+++###^^^@@@ */
+ };
+
+ int a = 1, b = 20;
+
+ do
+ {
+ int i = (a + b) / 2;
+ if (val > LB_VAL[i])
+ a = i + 1;
+ else
+ b = i;
+ }
+ while (a != b);
+
+ return a;
+}
+
+inline static int
+r_uint_wide (uint64_t val)
+{
+ int wide = r_uint_use (val);
+
+ wide = wide + (wide - 1) / 3;
+
+ return wide;
+}
+
+inline static void
+r_uint_fmt (char *buf, uint64_t val, int wide)
+{
+ char *p = buf + wide;
+
+ *p-- = 0;
+
+ while (1)
+ {
+ *p-- = ('0' + val % 10);
+ if ((val /= 10) == 0)
+ break;
+
+ *p-- = ('0' + val % 10);
+ if ((val /= 10) == 0)
+ break;
+
+ *p-- = ('0' + val % 10);
+ if ((val /= 10) == 0)
+ break;
+
+ *p-- = ',';
+ }
+
+ while (p >= buf)
+ *p-- = ' ';
+}
+
+int
+r_uint (char *buf, uint64_t val, int wide)
+{
+ const int size = r_uint_wide (val);
+
+ if (size > wide)
+ wide = size;
+
+ r_uint_fmt (buf, val, wide);
+
+ return wide;
+}
+
+inline int
+s_uint (char *buf, uint64_t val)
+{
+ char *p = buf;
+
+#define F_NUM(n) if (val >= n) { *p++ = '0' + val / n % 10; }
+#define C_NUM(n) if (val >= n) { *p++ = '0' + val / n % 10; *p++ = ','; }
+
+ if (val >= 10000000ul)
+ {
+ if (val >= 1000000000000ul)
+ {
+ F_NUM (10000000000000000000ul);
+ C_NUM (1000000000000000000ul);
+ F_NUM (100000000000000000ul);
+ F_NUM (10000000000000000ul);
+ C_NUM (1000000000000000ul);
+ F_NUM (100000000000000ul);
+ F_NUM (10000000000000ul);
+ C_NUM (1000000000000ul);
+ }
+ F_NUM (100000000000ul);
+ F_NUM (10000000000ul);
+ C_NUM (1000000000ul);
+ F_NUM (100000000ul);
+ F_NUM (10000000ul);
+ }
+ C_NUM (1000000ul);
+ F_NUM (100000ul);
+ F_NUM (10000ul);
+ C_NUM (1000ul);
+ F_NUM (100ul);
+ F_NUM (10ul);
+ *p++ = '0' + val % 10;
+ *p = 0;
+
+#undef F_NUM
+#undef C_NUM
+ return p - buf;
+}
+
+const char *
+f_uint (uint64_t val)
+{
+ char *buf = s_fmt_buf[(s_fmt_id++) & 63];
+ (void) s_uint (buf, val);
+ return buf;
+}
+
+#endif
+#ifdef PARSE_LB_H_
+
+#define IS_DIGIT(c) ((c) >= '0' && (c) <= '9')
+#define IS_hex(c) ((c) >= 'a' && (c) <= 'f')
+#define IS_HEX(c) ((c) >= 'A' && (c) <= 'F')
+
+uint64_t
+p_hex (const char *arg, const char **end)
+{
+ int i;
+ uint64_t val = 0;
+
+ while (*arg)
+ {
+ if (IS_DIGIT (*arg))
+ val = (val << 4) | (uint64_t) (*arg++ - '0');
+ else if (IS_hex (*arg))
+ val = (val << 4) | (uint64_t) (*arg++ - 'a' + 0xa);
+ else if (IS_HEX (*arg))
+ val = (val << 4) | (uint64_t) (*arg++ - 'A' + 0xA);
+ else
+ break;
+ if (val > 0x0FFFffffFFFFffff)
+ break;
+ }
+
+ if (end)
+ *end = arg;
+ return val;
+}
+
+#define P_UINT_RET(ret, out) ((*end = (out)), (ret))
+
+uint64_t
+p_uint (const char *arg, uint64_t max, const char **end)
+{
+ int i;
+ uint64_t v;
+ const char *out;
+
+ if (!end)
+ end = &out;
+
+ if (!arg)
+ goto P_UINT_ERR;
+
+ if (*arg == '0')
+ {
+ if (IS_DIGIT (arg[1]))
+ goto P_UINT_ERR;
+ return P_UINT_RET (0, arg + 1);
+ }
+
+ if (!IS_DIGIT (*arg))
+ return P_UINT_RET (0, NULL);
+
+ v = *arg++ - '0';
+ if (v > max)
+ goto P_UINT_ERR;
+
+ for (i = 2; i <= 19; ++i)
+ {
+ if (!IS_DIGIT (*arg))
+ return P_UINT_RET (v, arg);
+ v = v * 10 + (*arg++ - '0');
+ if (v > max)
+ goto P_UINT_ERR;
+ }
+
+ if (IS_DIGIT (*arg))
+ {
+ uint64_t n;
+ if (v > (UINT64_MAX / 10))
+ goto P_UINT_ERR;
+ n = v * 10;
+ if (UINT64_MAX - n > (*arg - '0'))
+ goto P_UINT_ERR;
+ v = n + (*arg - '0');
+ if (v > max)
+ goto P_UINT_ERR;
+ arg++;
+ if (IS_DIGIT (*arg))
+ goto P_UINT_ERR;
+ }
+
+ return P_UINT_RET (v, arg);
+
+P_UINT_ERR:
+ return P_UINT_RET (UINT64_MAX, NULL);
+}
+
+inline uint32_t
+p_ip (const char **arg)
+{
+ uint32_t b1, b2, b3, b4;
+ const char *p = *arg;
+
+ b1 = (uint32_t) p_uint (p, 255, &p);
+ if (!p || *p++ != '.')
+ goto P_IP_ERR;
+ b2 = (uint32_t) p_uint (p, 255, &p);
+ if (!p || *p++ != '.')
+ goto P_IP_ERR;
+ b3 = (uint32_t) p_uint (p, 255, &p);
+ if (!p || *p++ != '.')
+ goto P_IP_ERR;
+ b4 = (uint32_t) p_uint (p, 255, &p);
+ if (!p)
+ goto P_IP_ERR;
+
+ *arg = p;
+ return (b1 << 24) | (b2 << 16) | (b3 << 8) | b4;
+
+P_IP_ERR:
+ *arg = NULL;
+ return 0;
+}
+
+int
+p_addr (const char *arg, struct sockaddr_in *addr)
+{
+ uint16_t port;
+
+ if (*arg != ':')
+ {
+ uint32_t ip = p_ip (&arg);
+ if (!arg)
+ return -1;
+ addr->sin_addr.s_addr = htonl (ip);
+ if (*arg == 0)
+ return 0;
+ if (*arg != ':')
+ return -1;
+ arg++;
+ }
+
+ port = (uint16_t) p_uint (arg, 0xffff, &arg);
+ if (!arg || *arg != 0)
+ return -1;
+ addr->sin_port = htons (port);
+
+ return 0;
+}
+
+const char *
+p_addr_set (const char *arg, struct inaddrs *addr, uint32_t flag)
+{
+ addr->ip = p_ip (&arg);
+ if (!arg)
+ return NULL;
+
+ if (!(flag & PA_NO_TO_IP) && *arg == '-')
+ {
+ uint8_t to;
+ to = (uint8_t) p_uint (arg + 1, 255, &arg);
+ if (!arg)
+ return NULL;
+ addr->ip_num = to - (uint8_t) addr->ip;
+ if (addr->ip_num >= 0)
+ ++addr->ip_num;
+ else if (flag & PA_MAY_INV_IP)
+ --addr->ip_num;
+ else
+ return NULL;
+ }
+ else if (!(flag & PA_NO_NUM_IP) && *arg == '+')
+ {
+ addr->ip_num = (int) p_uint (arg + 1, 0x7FFFffff, &arg);
+ if (!arg || addr->ip_num == 0 || 0xFFFFFFFF - addr->ip < addr->ip_num)
+ return NULL;
+ }
+ else
+ {
+ addr->ip_num = 1;
+ }
+
+ if ((flag & PA_DEF_PORT) == PA_NO_PORT)
+ return arg;
+
+ if (*arg != ':')
+ {
+ if ((flag & PA_DEF_PORT) == PA_MUST_PORT)
+ return NULL;
+ if ((flag & PA_DEF_PORT) == PA_DEF_PORT)
+ {
+ addr->port = (uint16_t) (flag);
+ addr->port_num = 1;
+ }
+ else
+ {
+ addr->port = 0;
+ addr->port_num = 0;
+ }
+ return arg;
+ }
+
+ addr->port = (uint16_t) p_uint (arg + 1, 0xffff, &arg);
+ if (!arg)
+ return NULL;
+
+ if (!(flag & PA_NO_TO_PORT) && *arg == '-')
+ {
+ uint16_t to = (uint16_t) p_uint (arg + 1, 0xffff, &arg);
+ if (!arg || to < addr->port)
+ return NULL;
+ addr->port_num = to - addr->port + 1;
+ }
+ else if (!(flag & PA_NO_NUM_PORT) && *arg == '+')
+ {
+ addr->port_num = (uint16_t) p_uint (arg + 1, 0xffff, &arg);
+ if (!arg || addr->port_num == 0 || 0xFFFF - addr->port < addr->port_num)
+ return NULL;
+ }
+ else
+ {
+ addr->port_num = 1;
+ }
+
+ if (flag & PA_MULTI_ONE)
+ {
+ if (addr->ip_num > 1 && addr->port_num > 1)
+ return NULL;
+ }
+
+ return arg;
+}
+
+inline static const char *
+pal_trim (const char *arg, uint32_t flag)
+{
+ if (flag & PAL_NO_SPACE)
+ return arg;
+
+ if (flag & PAL_WITH_NL)
+ {
+ while (*arg == ' ' || *arg == '\t' || *arg == '\r' || *arg == '\n')
+ arg++;
+ }
+ else
+ {
+ while (*arg == ' ' || *arg == '\t')
+ arg++;
+ }
+
+ return arg;
+}
+
+int
+p_addr_list (const char *arg, struct inaddrs *list, int num, uint32_t flag,
+ const char **end)
+{
+ int count = 0;
+
+ while (count < num)
+ {
+ arg = pal_trim (arg, flag);
+ arg = p_addr_set (arg, list, flag);
+ count++;
+ if (!arg)
+ return -count;
+ arg = pal_trim (arg, flag);
+ if (*arg != ',')
+ break;
+ arg++;
+ list++;
+ }
+
+ if (end)
+ *end = arg;
+ else if (*arg)
+ return -count;
+
+ return count;
+}
+
+int
+addr_total (const struct inaddrs *list, int num, uint32_t mode)
+{
+ int total = 0;
+
+ mode &= PAL_CROSS_MASK;
+
+ for (--num; num >= 0; --num)
+ {
+ if (mode == PAL_IP_X_PORT || mode == PAL_PORT_X_IP)
+ {
+ total += list[num].ip_num * list[num].port_num;
+ }
+ else if (mode == PAL_INC_BOTH)
+ {
+ int iip = 0;
+ uint16_t iport = 0;
+ do
+ {
+ total++;
+ if (++iip == list[num].ip_num)
+ iip = 0;
+ if (++iport == list[num].port_num)
+ iport = 0;
+ }
+ while (iip != 0 && iport != 0);
+ }
+ else
+ return -1;
+ }
+
+ return total;
+}
+
+int
+addr_layout (const struct inaddrs *list, int list_num,
+ struct sockaddr_in *addr, int addr_num, uint32_t mode)
+{
+ uint16_t ipt;
+ int i, iip, count = 0;
+
+ mode &= PAL_CROSS_MASK;
+
+ if (mode == PAL_IP_X_PORT)
+ {
+ for (i = 0; i < list_num; ++i)
+ {
+ if (count + list[i].ip_num * list[i].port_num > addr_num)
+ return -1;
+ for (iip = 0; iip < list[i].ip_num; ++iip)
+ {
+ for (ipt = 0; ipt < list[i].port_num; ++ipt)
+ {
+ addr[count].sin_family = AF_INET;
+ addr[count].sin_addr.s_addr = htonl (list[i].ip + iip);
+ addr[count].sin_port = htons (list[i].port + ipt);
+ count++;
+ }
+ }
+ }
+ }
+ else if (mode == PAL_PORT_X_IP)
+ {
+ for (i = 0; i < list_num; ++i)
+ {
+ if (count + list[i].ip_num * list[i].port_num > addr_num)
+ return -1;
+ for (ipt = 0; ipt < list[i].port_num; ++ipt)
+ {
+ for (iip = 0; iip < list[i].ip_num; ++iip)
+ {
+ addr[count].sin_family = AF_INET;
+ addr[count].sin_addr.s_addr = htonl (list[i].ip + iip);
+ addr[count].sin_port = htons (list[i].port + ipt);
+ count++;
+ }
+ }
+ }
+ }
+ else if (mode == PAL_INC_BOTH)
+ {
+ for (i = 0; i < list_num; ++i)
+ {
+ do
+ {
+ if (count >= addr_num)
+ return -1;
+ addr[count].sin_family = AF_INET;
+ addr[count].sin_addr.s_addr = htonl (list[i].ip + iip);
+ addr[count].sin_port = htons (list[i].port + ipt);
+ count++;
+ if (++iip >= list[i].ip_num)
+ iip = 0;
+ if (++ipt >= list[i].port_num)
+ ipt = 0;
+ }
+ while (iip != 0 && ipt != 0);
+ }
+ }
+ else
+ {
+ return -1;
+ }
+
+ return count;
+}
+
+inline static const char *
+p_ip6_se (const char *p, uint16_t * val)
+{
+ int i;
+ uint32_t v = 0;
+
+ for (i = 0; i < 4; ++i)
+ {
+ if (p[i] >= '0' && p[i] <= '9')
+ v = (v << 4) + p[i] - '0';
+ else if (p[i] >= 'a' && p[i] <= 'f')
+ v = (v << 4) + p[i] - 'a' + 10;
+ else if (p[i] >= 'A' && p[i] <= 'F')
+ v = (v << 4) + p[i] - 'A' + 10;
+ else
+ break;
+ }
+
+ if (i == 0)
+ return NULL;
+
+ *val = htons (v);
+ return p + i;
+}
+
+const char *
+p_ip6 (const char *pos, struct in6_addr *ip)
+{
+ int zero = -1, num = 0;
+ const char *last;
+
+ if (*pos == ':')
+ {
+ pos++;
+ if (*pos != ':')
+ return NULL;
+ pos++;
+ zero = 0;
+ }
+
+ last = pos;
+
+ while (*pos)
+ {
+ pos = p_ip6_se (pos, &ip->s6_addr16[num]);
+ if (!pos)
+ {
+ if (zero == num)
+ break;
+ return NULL;
+ }
+
+ num++;
+ if (num == 8)
+ break;
+
+ if (*pos == ':')
+ {
+ pos++;
+ if (*pos == ':')
+ {
+ if (zero >= 0)
+ return NULL;
+ zero = num;
+ pos++;
+ }
+ last = pos;
+ }
+ else if (*pos == '.')
+ {
+ if (num > 6)
+ return NULL;
+ *(uint32_t *) (&ip->s6_addr16[num - 1]) = htonl (p_ip (&last));
+ if (!last)
+ return NULL;
+ pos = last;
+ num++;
+ break;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ if (num == 0)
+ {
+ if (zero != 0)
+ return NULL;
+ ip->s6_addr32[0] = htonl (0);
+ ip->s6_addr32[1] = htonl (0);
+ ip->s6_addr32[2] = htonl (0);
+ ip->s6_addr32[3] = htonl (0);
+ return pos;
+ }
+
+ if (num < 8)
+ {
+ int i, cp;
+ if (zero < 0)
+ return NULL;
+ /* move */
+ for (i = num - 1, cp = 7; i >= zero; --i)
+ ip->s6_addr16[cp--] = ip->s6_addr16[i];
+ /* fill 0 */
+ for (i = num, cp = zero; i < 8; ++i)
+ ip->s6_addr16[cp++] = htons (0);
+ }
+ else if (zero >= 0)
+ {
+ return NULL;
+ }
+
+ return pos;
+}
+
+int
+p_addr6 (const char *arg, struct sockaddr_in6 *addr)
+{
+ uint16_t port;
+
+ if (*arg != '.')
+ {
+ arg = p_ip6 (arg, &addr->sin6_addr);
+ if (!arg)
+ return -1;
+ if (*arg == 0)
+ return 0;
+ if (*arg != '.')
+ return -1;
+ arg++;
+ }
+
+ port = (uint16_t) p_uint (arg, 0xffff, &arg);
+ if (!arg || *arg != 0)
+ return -1;
+ addr->sin6_port = htons (port);
+
+ return 0;
+}
+
+#endif
+#ifdef UNIT_LB_H_
+
+const static uint64_t UNITS[UNIT_NUM] = {
+ [UNIT_1] = 1,
+ [UNIT_k] = 1000,
+ [UNIT_m] = 1000 * 1000,
+ [UNIT_g] = 1000 * 1000 * 1000,
+ [UNIT_w] = 10000,
+ [UNIT_K] = 1024,
+ [UNIT_M] = 1024 * 1024,
+ [UNIT_G] = 1024 * 1024 * 1024,
+
+ [UNIT_hour] = 60 * 60,
+ [UNIT_min] = 60,
+ [UNIT_sec] = 1,
+
+ [UNIT_hn] = 1000ull * 1000 * 1000 * 60 * 60,
+ [UNIT_mn] = 1000ull * 1000 * 1000 * 60,
+ [UNIT_sn] = 1000 * 1000 * 1000,
+ [UNIT_1n] = 1000 * 1000 * 1000,
+ [UNIT_ms] = 1000 * 1000,
+ [UNIT_us] = 1000,
+ [UNIT_ns] = 1,
+
+ [UNIT_PC] = 1,
+};
+
+#define P_UNIT_END(ret, end) ({ \
+ *arg = (end); \
+ if (unit) *unit = UNITS[ret]; \
+ ret; \
+})
+
+int
+p_unit (const char **arg, int mask, uint64_t * unit)
+{
+ const char *opt = *arg;
+ int ret;
+
+ switch (*opt)
+ {
+ case 'w':
+ ret = UNIT_w;
+ break;
+ case 'm':
+ if ((mask & UB_ms) && opt[1] == 's')
+ return P_UNIT_END (UNIT_ms, opt + 2);
+ if (mask & UB_min)
+ return P_UNIT_END (UNIT_min, opt + 1);
+ ret = UNIT_m;
+ break;
+ case 'k':
+ ret = UNIT_k;
+ break;
+ case 'g':
+ ret = UNIT_g;
+ break;
+
+ case 'h':
+ ret = UNIT_hour;
+ break;
+ case 's':
+ ret = UNIT_sec;
+ break;
+ case 'u':
+ if ((mask & UB_us) && opt[1] == 's')
+ return P_UNIT_END (UNIT_us, opt + 2);
+ goto NO_UNIT;
+ case 'n':
+ if ((mask & UB_ns) && opt[1] == 's')
+ return P_UNIT_END (UNIT_ns, opt + 2);
+ goto NO_UNIT;
+
+ case '%':
+ ret = UNIT_PC;
+ break;
+
+ case 'K':
+ ret = UNIT_K;
+ break;
+ case 'M':
+ ret = UNIT_M;
+ break;
+ case 'G':
+ ret = UNIT_G;
+ break;
+
+ default:
+ goto NO_UNIT;
+ }
+
+ if ((1 << ret) & mask)
+ return P_UNIT_END (ret, opt + 1);
+
+NO_UNIT:
+ if (0 == (mask & UB_1))
+ return -1;
+
+ return P_UNIT_END (UNIT_1, opt);
+}
+
+#endif
+#ifdef CACHED_OUTPUT_LB_H_
+
+int
+co_app_ch (char buf[], char ch)
+{
+ struct cohead *head = (struct cohead *) buf;
+
+ buf += sizeof (struct cohead);
+
+ if (head->free > 3)
+ {
+ buf += (head->size - head->free);
+ buf[0] = ch;
+ buf[1] = 0;
+ head->free -= 1;
+ }
+ else
+ {
+ (void) fprintf (CO_OUT (head), "%s%c", buf, ch);
+ buf[0] = 0;
+ head->free = head->size;
+ }
+
+ return 1;
+}
+
+int
+co_append (char buf[], cosize_t max, const char *fmt, ...)
+{
+ int ret;
+ va_list ap;
+ struct cohead *head = (struct cohead *) buf;
+
+ /* no space for max+1 size -> output if cached */
+ if (max >= head->free && head->free < head->size)
+ _co_flush (head);
+
+ /* enough space -> try cache format */
+ if (max < head->free)
+ {
+ char *p = buf + (sizeof (struct cohead) + head->size - head->free);
+ va_start (ap, fmt);
+ ret = vsnprintf (p, head->free, fmt, ap);
+ va_end (ap);
+ if (ret >= 0 && ret < head->free)
+ {
+ head->free -= ret;
+ return ret;
+ }
+ }
+
+ /* no space or format failed -> output if cached */
+ if (head->free != head->size)
+ _co_flush (head);
+
+ /* direct output */
+ va_start (ap, fmt);
+ ret = fprintf (CO_OUT (head), fmt, ap);
+ va_end (ap);
+
+ return ret;
+}
+
+int
+co_wr_uint (char buf[], uint64_t val, int wide)
+{
+ struct cohead *head = (struct cohead *) buf;
+ int size = r_uint_wide (val);
+ char *p;
+
+ if (size > wide)
+ wide = size;
+
+ if (head->free <= wide)
+ _co_flush (head);
+
+ if (head->free <= wide)
+ {
+ assert (0);
+ }
+
+ p = buf + (sizeof (struct cohead) + head->size - head->free);
+
+ r_uint_fmt (p, val, wide);
+
+ head->free -= wide;
+
+ return wide;
+}
+
+#endif
+
+#ifdef SYSTEM_LB_H_
+
+pthread_t
+lb_thread (void *(*proc) (void *), void *arg, const char *fmt, ...)
+{
+ pthread_t tid;
+ int ret;
+
+ ret = pthread_create (&tid, NULL, proc, arg);
+ if (ret)
+ return 0;
+
+ if (fmt)
+ {
+ char name[20];
+ va_list args;
+
+ va_start (args, fmt);
+ ret = vsnprintf (name, sizeof (name), fmt, args);
+ va_end (args);
+
+ if (ret > 0)
+ {
+ name[sizeof (name) - 1] = 0;
+ (void) pthread_setname_np (tid, name);
+ }
+ }
+
+ return tid;
+}
+
+static void
+lb_sigsegv_proc (int s)
+{
+ int num;
+ void *buf[128];
+
+ out ("Signal SIGSEGV, Segmentation fault!\n");
+
+ num = backtrace (buf, 128);
+ if (num > 0)
+ backtrace_symbols_fd (buf, num, STDOUT_FILENO);
+ exit (1);
+}
+
+void
+lb_sigsegv_setup ()
+{
+ struct sigaction s = { 0 };
+
+ (void) sigemptyset (&s.sa_mask);
+
+ s.sa_flags = SA_NODEFER;
+ s.sa_handler = (void *) lb_sigsegv_proc;
+ (void) sigaction (SIGSEGV, &s, NULL);
+}
+
+#endif
+
+#ifdef KERNEL_SYSCALL_API
+
+#define KAPI(name) (typeof name) *k_##name = ##name;
+#include "kapi.h"
+#undef API
+
+void
+kapi_init ()
+{
+#define KAPI(name) k_##name = ld_load;
+}
+
+#endif