summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorQiuwen Lu <[email protected]>2016-12-01 10:22:32 +0800
committerQiuwen Lu <[email protected]>2016-12-01 10:22:32 +0800
commita19fa9f23845e4a8ceb40aad480bab917d054f3e (patch)
treefddf9743fa401e8ab3ea3a60998898b24537ebd2
parente63d5b8533310a3e3baca7985fe6fb3372caecec (diff)
通过JSON输出运行状态监测、统计信息
-rw-r--r--core/include/mr_buffer.h6
-rw-r--r--core/src/buffer.c52
-rw-r--r--core/src/stat.c34
-rw-r--r--service/CMakeLists.txt2
-rw-r--r--service/include/sc_common.h2
-rw-r--r--service/src/cJSON.c2233
-rw-r--r--service/src/cJSON.h165
-rw-r--r--service/src/config.c54
-rw-r--r--service/src/core.c48
-rw-r--r--service/src/monit.c107
-rw-r--r--service/src/register.c43
11 files changed, 2672 insertions, 74 deletions
diff --git a/core/include/mr_buffer.h b/core/include/mr_buffer.h
index 67a5db5..c15b5da 100644
--- a/core/include/mr_buffer.h
+++ b/core/include/mr_buffer.h
@@ -28,8 +28,12 @@ int mr_buffer_user_pool_produce(struct mr_core_instance* instance, unsigned int
int mr_buffer_pool_produce(struct mr_core_instance* instance, unsigned int socket_id, unsigned int data_size,
unsigned int pool_size, unsigned int cache_size);
-int mr_buffer_ctrlzone_register(struct mr_core_instance* instance, uint8_t id, uint8_t size);
+int mr_buffer_ctrlzone_register(struct mr_core_instance* instance, const char* cz_sym,
+ uint8_t id, uint8_t size);
+
+int mr_buffer_ctrlzone_lookup(struct mr_core_instance* instance, const char* cz_sym,
+ uint8_t * id, uint8_t * size);
#ifdef __cplusplus
}
diff --git a/core/src/buffer.c b/core/src/buffer.c
index b197528..e0b0793 100644
--- a/core/src/buffer.c
+++ b/core/src/buffer.c
@@ -27,11 +27,19 @@ struct mrb_zone_idx_t
struct mrb_priv_zone_t
{
- struct rte_mempool * next;
+ struct rte_mbuf * next;
uint8_t cz_num;
struct mrb_zone_idx_t idx[0];
}__rte_packed;
+struct mrb_zone_info_t
+{
+ char symbol[MR_SYMBOL_MAX];
+ unsigned int cz_id;
+ unsigned int size;
+ unsigned int in_use;
+};
+
struct whole_mrb_pool_t
{
struct mrb_pool_t external; //"external" must be the first member of this struct
@@ -40,6 +48,7 @@ struct whole_mrb_pool_t
unsigned int total_ctrl_zone_size;
uint8_t ctrlzone_num;
+ struct mrb_zone_info_t ctrlzone_info[MRB_MAX_CTRLZONE_NUM];
struct mrb_zone_idx_t ctrlzone[MRB_MAX_CTRLZONE_NUM];
};
@@ -185,28 +194,61 @@ int mr_buffer_pool_produce(struct mr_core_instance* instance, unsigned int socke
return i;
}
-int mr_buffer_ctrlzone_register(struct mr_core_instance* instance, uint8_t id, uint8_t size)
+int mr_buffer_ctrlzone_register(struct mr_core_instance* instance, const char* cz_sym,
+ uint8_t id, uint8_t size)
{
struct whole_mrb_pool_t *_handle = (struct whole_mrb_pool_t *)instance->mrb_pool_handle;
if (_handle->ctrlzone_num >= MRB_MAX_CTRLZONE_NUM)
{
- return -1;
+ return -EOVERFLOW;
}
if (_handle->ctrlzone[id].size != 0)
{
- return -1;
+ return -EEXIST;
+ }
+
+ if(_handle->ctrlzone_info[id].in_use)
+ {
+ return -EEXIST;
}
+ snprintf(_handle->ctrlzone_info[id].symbol, sizeof(_handle->ctrlzone_info[id].symbol), "%s", cz_sym);
+ _handle->ctrlzone_info[id].size = size;
+ _handle->ctrlzone_info[id].cz_id = id;
+ _handle->ctrlzone_info[id].in_use = 1;
+
_handle->ctrlzone[id].size = size;
_handle->ctrlzone[id].offset = _handle->total_ctrl_zone_size;
_handle->total_ctrl_zone_size += (size + sizeof(struct mrb_zone_idx_t));
_handle->ctrlzone_num++;
-
return 0;
}
+int mr_buffer_ctrlzone_lookup(struct mr_core_instance* instance, const char* cz_sym,
+ uint8_t * id, uint8_t * size)
+{
+ struct whole_mrb_pool_t *_handle = (struct whole_mrb_pool_t *)instance->mrb_pool_handle;
+ for(int i = 0; i < _handle->ctrlzone_num; i++)
+ {
+ struct mrb_zone_idx_t * cz = &_handle->ctrlzone[i];
+ struct mrb_zone_info_t * czinfo = &_handle->ctrlzone_info[i];
+ if (strcmp(czinfo->symbol, cz_sym) != 0) continue;
+
+ assert(cz->size != 0);
+ assert(czinfo->in_use > 0);
+ assert(czinfo->size > 0);
+ assert(czinfo->cz_id == i);
+
+ *id = czinfo->cz_id;
+ *size = czinfo->size;
+ return 0;
+ }
+
+ return -1;
+}
+
void * marsio_buff_ctrlzone(marsio_buff_t *mr_buff, uint8_t id)
{
assert(id < mrbuf_cz_num(mr_buff));
diff --git a/core/src/stat.c b/core/src/stat.c
index 72e3d60..f81361d 100644
--- a/core/src/stat.c
+++ b/core/src/stat.c
@@ -11,27 +11,6 @@
#include <mr_stat.h>
#include <mr_core.h>
#include <mr_runtime.h>
-#include "MESA_prof_load.h"
-
-#ifndef MR_STAT_OPT_DEFAULT_DEV_STAT_ENABLE
-#define MR_STAT_OPT_DEFAULT_DEV_STAT_ENABLE 1
-#endif
-
-#ifndef MR_STAT_OPT_DEFAULT_VNODE_STAT_ENABLE
-#define MR_STAT_OPT_DEFAULT_VNODE_STAT_ENABLE 1
-#endif
-
-#ifndef MR_STAT_OPT_DEFAULT_PERF_STAT_ENABLE
-#define MR_STAT_OPT_DEFAULT_PERF_STAT_ENABLE 1
-#endif
-
-#ifndef MR_STAT_OPT_DEFAULT_APP_STAT_ENABLE
-#define MR_STAT_OPT_DEFAULT_APP_STAT_ENABLE 1
-#endif
-
-#ifndef MR_STAT_OPT_DEFAULT_EVENT_STAT_ENABLE
-#define MR_STAT_OPT_DEFAULT_EVENT_STAT_ENABLE 1
-#endif
struct stat_ctx
{
@@ -92,19 +71,6 @@ int stat_init(struct mr_core_instance * core_instance)
int stat_config(struct mr_core_instance * core_instance)
{
- struct mr_global_config * g_cfg = core_instance->g_cfg;
- struct stat_ctx * module_ctx = mr_core_default_instance_get()->stat_ctx;
-
- MESA_load_profile_uint_def(g_cfg->glob_cfg_file, "stat", "device_stat_enable",
- &module_ctx->device_stat_enable, MR_STAT_OPT_DEFAULT_DEV_STAT_ENABLE);
- MESA_load_profile_uint_def(g_cfg->glob_cfg_file, "stat", "vnode_stat_enable",
- &module_ctx->vnode_stat_enable, MR_STAT_OPT_DEFAULT_VNODE_STAT_ENABLE);
- MESA_load_profile_uint_def(g_cfg->glob_cfg_file, "stat", "perf_stat_enable",
- &module_ctx->perf_stat_enable, MR_STAT_OPT_DEFAULT_PERF_STAT_ENABLE);
- MESA_load_profile_uint_def(g_cfg->glob_cfg_file, "stat", "app_stat_enable",
- &module_ctx->app_stat_enable, MR_STAT_OPT_DEFAULT_APP_STAT_ENABLE);
- MESA_load_profile_uint_def(g_cfg->glob_cfg_file, "stat", "event_stat_enable",
- &module_ctx->event_stat_enable, MR_STAT_OPT_DEFAULT_EVENT_STAT_ENABLE);
return 0;
}
diff --git a/service/CMakeLists.txt b/service/CMakeLists.txt
index 8747c73..b71dd11 100644
--- a/service/CMakeLists.txt
+++ b/service/CMakeLists.txt
@@ -7,7 +7,7 @@ include_directories(${DPDK_INCLUDE_DIR})
include_directories(include)
add_definitions(${DPDK_C_PREDEFINED})
-add_executable(zcpd src/core.c src/config.c src/register.c src/rxtx.c src/ldbc.c)
+add_executable(zcpd src/cJSON.c src/core.c src/config.c src/register.c src/rxtx.c src/ldbc.c src/monit.c)
target_link_libraries(zcpd ${DPDK_LIBRARY} MESA_prof_load_static)
target_link_libraries(zcpd rt pthread dl core stack)
target_include_directories(zcpd INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include/")
diff --git a/service/include/sc_common.h b/service/include/sc_common.h
index d69108b..84963c7 100644
--- a/service/include/sc_common.h
+++ b/service/include/sc_common.h
@@ -96,6 +96,8 @@ struct sc_instance
char local_cfgfile[MR_STRING_MAX];
/* ������־�ļ�λ�� */
char local_logfile[MR_STRING_MAX];
+ /* ״̬����ļ� */
+ char local_monitfile[MR_STRING_MAX];
/* CPU���룬�����������CPU������ */
cpu_mask_t cpu_mask;
/* ���õ��豸�б� */
diff --git a/service/src/cJSON.c b/service/src/cJSON.c
new file mode 100644
index 0000000..766e558
--- /dev/null
+++ b/service/src/cJSON.c
@@ -0,0 +1,2233 @@
+/*
+ Copyright (c) 2009 Dave Gamble
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+/* cJSON */
+/* JSON parser in C. */
+
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <float.h>
+#include <limits.h>
+#include <ctype.h>
+#include "cJSON.h"
+
+/* Determine the number of bits that an integer has using the preprocessor */
+#if INT_MAX == 32767
+ /* 16 bits */
+ #define INTEGER_SIZE 0x0010
+#elif INT_MAX == 2147483647
+ /* 32 bits */
+ #define INTEGER_SIZE 0x0100
+#elif INT_MAX == 9223372036854775807
+ /* 64 bits */
+ #define INTEGER_SIZE 0x1000
+#else
+ #error "Failed to determine the size of an integer"
+#endif
+
+/* define our own boolean type */
+typedef int cjbool;
+#define true ((cjbool)1)
+#define false ((cjbool)0)
+
+static const char *global_ep = NULL;
+
+const char *cJSON_GetErrorPtr(void)
+{
+ return global_ep;
+}
+
+/* case insensitive strcmp */
+static int cJSON_strcasecmp(const char *s1, const char *s2)
+{
+ if (!s1)
+ {
+ return (s1 == s2) ? 0 : 1; /* both NULL? */
+ }
+ if (!s2)
+ {
+ return 1;
+ }
+ for(; tolower(*(const unsigned char *)s1) == tolower(*(const unsigned char *)s2); ++s1, ++s2)
+ {
+ if (*s1 == '\0')
+ {
+ return 0;
+ }
+ }
+
+ return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2);
+}
+
+static void *(*cJSON_malloc)(size_t sz) = malloc;
+static void (*cJSON_free)(void *ptr) = free;
+
+static char* cJSON_strdup(const char* str)
+{
+ size_t len = 0;
+ char *copy = NULL;
+
+ len = strlen(str) + 1;
+ if (!(copy = (char*)cJSON_malloc(len)))
+ {
+ return NULL;
+ }
+ memcpy(copy, str, len);
+
+ return copy;
+}
+
+void cJSON_InitHooks(cJSON_Hooks* hooks)
+{
+ if (!hooks)
+ {
+ /* Reset hooks */
+ cJSON_malloc = malloc;
+ cJSON_free = free;
+ return;
+ }
+
+ cJSON_malloc = (hooks->malloc_fn) ? hooks->malloc_fn : malloc;
+ cJSON_free = (hooks->free_fn) ? hooks->free_fn : free;
+}
+
+/* Internal constructor. */
+static cJSON *cJSON_New_Item(void)
+{
+ cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON));
+ if (node)
+ {
+ memset(node, '\0', sizeof(cJSON));
+ }
+
+ return node;
+}
+
+/* Delete a cJSON structure. */
+void cJSON_Delete(cJSON *c)
+{
+ cJSON *next = NULL;
+ while (c)
+ {
+ next = c->next;
+ if (!(c->type & cJSON_IsReference) && c->child)
+ {
+ cJSON_Delete(c->child);
+ }
+ if (!(c->type & cJSON_IsReference) && c->valuestring)
+ {
+ cJSON_free(c->valuestring);
+ }
+ if (!(c->type & cJSON_StringIsConst) && c->string)
+ {
+ cJSON_free(c->string);
+ }
+ cJSON_free(c);
+ c = next;
+ }
+}
+
+/* Parse the input text to generate a number, and populate the result into item. */
+static const char *parse_number(cJSON *item, const char *num)
+{
+ double n = 0;
+ double sign = 1;
+ double scale = 0;
+ int subscale = 0;
+ int signsubscale = 1;
+
+ /* Has sign? */
+ if (*num == '-')
+ {
+ sign = -1;
+ num++;
+ }
+ /* is zero */
+ if (*num == '0')
+ {
+ num++;
+ }
+ /* Number? */
+ if ((*num >= '1') && (*num <= '9'))
+ {
+ do
+ {
+ n = (n * 10.0) + (*num++ - '0');
+ }
+ while ((*num >= '0') && (*num<='9'));
+ }
+ /* Fractional part? */
+ if ((*num == '.') && (num[1] >= '0') && (num[1] <= '9'))
+ {
+ num++;
+ do
+ {
+ n = (n *10.0) + (*num++ - '0');
+ scale--;
+ } while ((*num >= '0') && (*num <= '9'));
+ }
+ /* Exponent? */
+ if ((*num == 'e') || (*num == 'E'))
+ {
+ num++;
+ /* With sign? */
+ if (*num == '+')
+ {
+ num++;
+ }
+ else if (*num == '-')
+ {
+ signsubscale = -1;
+ num++;
+ }
+ /* Number? */
+ while ((*num>='0') && (*num<='9'))
+ {
+ subscale = (subscale * 10) + (*num++ - '0');
+ }
+ }
+
+ /* number = +/- number.fraction * 10^+/- exponent */
+ n = sign * n * pow(10.0, (scale + subscale * signsubscale));
+
+ item->valuedouble = n;
+ item->valueint = (int)n;
+ item->type = cJSON_Number;
+
+ return num;
+}
+
+/* calculate the next largest power of 2 */
+static int pow2gt (int x)
+{
+ --x;
+
+ x |= x >> 1;
+ x |= x >> 2;
+ x |= x >> 4;
+#if INTEGER_SIZE & 0x1110 /* at least 16 bit */
+ x |= x >> 8;
+#endif
+#if INTEGER_SIZE & 0x1100 /* at least 32 bit */
+ x |= x >> 16;
+#endif
+#if INT_SIZE & 0x1000 /* 64 bit */
+ x |= x >> 32;
+#endif
+
+ return x + 1;
+}
+
+typedef struct
+{
+ char *buffer;
+ int length;
+ int offset;
+} printbuffer;
+
+/* realloc printbuffer if necessary to have at least "needed" bytes more */
+static char* ensure(printbuffer *p, int needed)
+{
+ char *newbuffer = NULL;
+ int newsize = 0;
+ if (!p || !p->buffer)
+ {
+ return NULL;
+ }
+ needed += p->offset;
+ if (needed <= p->length)
+ {
+ return p->buffer + p->offset;
+ }
+
+ newsize = pow2gt(needed);
+ newbuffer = (char*)cJSON_malloc(newsize);
+ if (!newbuffer)
+ {
+ cJSON_free(p->buffer);
+ p->length = 0;
+ p->buffer = NULL;
+
+ return NULL;
+ }
+ if (newbuffer)
+ {
+ memcpy(newbuffer, p->buffer, p->length);
+ }
+ cJSON_free(p->buffer);
+ p->length = newsize;
+ p->buffer = newbuffer;
+
+ return newbuffer + p->offset;
+}
+
+/* calculate the new length of the string in a printbuffer */
+static int update(const printbuffer *p)
+{
+ char *str = NULL;
+ if (!p || !p->buffer)
+ {
+ return 0;
+ }
+ str = p->buffer + p->offset;
+
+ return p->offset + strlen(str);
+}
+
+/* Render the number nicely from the given item into a string. */
+static char *print_number(const cJSON *item, printbuffer *p)
+{
+ char *str = NULL;
+ double d = item->valuedouble;
+ /* special case for 0. */
+ if (d == 0)
+ {
+ if (p)
+ {
+ str = ensure(p, 2);
+ }
+ else
+ {
+ str = (char*)cJSON_malloc(2);
+ }
+ if (str)
+ {
+ strcpy(str,"0");
+ }
+ }
+ /* value is an int */
+ else if ((fabs(((double)item->valueint) - d) <= DBL_EPSILON) && (d <= INT_MAX) && (d >= INT_MIN))
+ {
+ if (p)
+ {
+ str = ensure(p, 21);
+ }
+ else
+ {
+ /* 2^64+1 can be represented in 21 chars. */
+ str = (char*)cJSON_malloc(21);
+ }
+ if (str)
+ {
+ sprintf(str, "%d", item->valueint);
+ }
+ }
+ /* value is a floating point number */
+ else
+ {
+ if (p)
+ {
+ /* This is a nice tradeoff. */
+ str = ensure(p, 64);
+ }
+ else
+ {
+ /* This is a nice tradeoff. */
+ str=(char*)cJSON_malloc(64);
+ }
+ if (str)
+ {
+ /* This checks for NaN and Infinity */
+ if ((d * 0) != 0)
+ {
+ sprintf(str, "null");
+ }
+ else if ((fabs(floor(d) - d) <= DBL_EPSILON) && (fabs(d) < 1.0e60))
+ {
+ sprintf(str, "%.0f", d);
+ }
+ else if ((fabs(d) < 1.0e-6) || (fabs(d) > 1.0e9))
+ {
+ sprintf(str, "%e", d);
+ }
+ else
+ {
+ sprintf(str, "%f", d);
+ }
+ }
+ }
+ return str;
+}
+
+/* parse 4 digit hexadecimal number */
+static unsigned parse_hex4(const char *str)
+{
+ unsigned h = 0;
+ /* first digit */
+ if ((*str >= '0') && (*str <= '9'))
+ {
+ h += (*str) - '0';
+ }
+ else if ((*str >= 'A') && (*str <= 'F'))
+ {
+ h += 10 + (*str) - 'A';
+ }
+ else if ((*str >= 'a') && (*str <= 'f'))
+ {
+ h += 10 + (*str) - 'a';
+ }
+ else /* invalid */
+ {
+ return 0;
+ }
+
+
+ /* second digit */
+ h = h << 4;
+ str++;
+ if ((*str >= '0') && (*str <= '9'))
+ {
+ h += (*str) - '0';
+ }
+ else if ((*str >= 'A') && (*str <= 'F'))
+ {
+ h += 10 + (*str) - 'A';
+ }
+ else if ((*str >= 'a') && (*str <= 'f'))
+ {
+ h += 10 + (*str) - 'a';
+ }
+ else /* invalid */
+ {
+ return 0;
+ }
+
+ /* third digit */
+ h = h << 4;
+ str++;
+ if ((*str >= '0') && (*str <= '9'))
+ {
+ h += (*str) - '0';
+ }
+ else if ((*str >= 'A') && (*str <= 'F'))
+ {
+ h += 10 + (*str) - 'A';
+ }
+ else if ((*str >= 'a') && (*str <= 'f'))
+ {
+ h += 10 + (*str) - 'a';
+ }
+ else /* invalid */
+ {
+ return 0;
+ }
+
+ /* fourth digit */
+ h = h << 4;
+ str++;
+ if ((*str >= '0') && (*str <= '9'))
+ {
+ h += (*str) - '0';
+ }
+ else if ((*str >= 'A') && (*str <= 'F'))
+ {
+ h += 10 + (*str) - 'A';
+ }
+ else if ((*str >= 'a') && (*str <= 'f'))
+ {
+ h += 10 + (*str) - 'a';
+ }
+ else /* invalid */
+ {
+ return 0;
+ }
+
+ return h;
+}
+
+/* first bytes of UTF8 encoding for a given length in bytes */
+static const unsigned char firstByteMark[7] =
+{
+ 0x00, /* should never happen */
+ 0x00, /* 0xxxxxxx */
+ 0xC0, /* 110xxxxx */
+ 0xE0, /* 1110xxxx */
+ 0xF0, /* 11110xxx */
+ 0xF8,
+ 0xFC
+};
+
+/* Parse the input text into an unescaped cstring, and populate item. */
+static const char *parse_string(cJSON *item, const char *str, const char **ep)
+{
+ const char *ptr = str + 1;
+ const char *end_ptr =str + 1;
+ char *ptr2 = NULL;
+ char *out = NULL;
+ int len = 0;
+ unsigned uc = 0;
+ unsigned uc2 = 0;
+
+ /* not a string! */
+ if (*str != '\"')
+ {
+ *ep = str;
+ return NULL;
+ }
+
+ while ((*end_ptr != '\"') && *end_ptr && ++len)
+ {
+ if (*end_ptr++ == '\\')
+ {
+ if (*end_ptr == '\0')
+ {
+ /* prevent buffer overflow when last input character is a backslash */
+ return NULL;
+ }
+ /* Skip escaped quotes. */
+ end_ptr++;
+ }
+ }
+
+ /* This is at most how long we need for the string, roughly. */
+ out = (char*)cJSON_malloc(len + 1);
+ if (!out)
+ {
+ return NULL;
+ }
+ item->valuestring = out; /* assign here so out will be deleted during cJSON_Delete() later */
+ item->type = cJSON_String;
+
+ ptr = str + 1;
+ ptr2 = out;
+ /* loop through the string literal */
+ while (ptr < end_ptr)
+ {
+ if (*ptr != '\\')
+ {
+ *ptr2++ = *ptr++;
+ }
+ /* escape sequence */
+ else
+ {
+ ptr++;
+ switch (*ptr)
+ {
+ case 'b':
+ *ptr2++ = '\b';
+ break;
+ case 'f':
+ *ptr2++ = '\f';
+ break;
+ case 'n':
+ *ptr2++ = '\n';
+ break;
+ case 'r':
+ *ptr2++ = '\r';
+ break;
+ case 't':
+ *ptr2++ = '\t';
+ break;
+ case '\"':
+ case '\\':
+ case '/':
+ *ptr2++ = *ptr;
+ break;
+ case 'u':
+ /* transcode utf16 to utf8. See RFC2781 and RFC3629. */
+ uc = parse_hex4(ptr + 1); /* get the unicode char. */
+ ptr += 4;
+ if (ptr >= end_ptr)
+ {
+ /* invalid */
+ *ep = str;
+ return NULL;
+ }
+ /* check for invalid. */
+ if (((uc >= 0xDC00) && (uc <= 0xDFFF)) || (uc == 0))
+ {
+ *ep = str;
+ return NULL;
+ }
+
+ /* UTF16 surrogate pairs. */
+ if ((uc >= 0xD800) && (uc<=0xDBFF))
+ {
+ if ((ptr + 6) > end_ptr)
+ {
+ /* invalid */
+ *ep = str;
+ return NULL;
+ }
+ if ((ptr[1] != '\\') || (ptr[2] != 'u'))
+ {
+ /* missing second-half of surrogate. */
+ *ep = str;
+ return NULL;
+ }
+ uc2 = parse_hex4(ptr + 3);
+ ptr += 6; /* \uXXXX */
+ if ((uc2 < 0xDC00) || (uc2 > 0xDFFF))
+ {
+ /* invalid second-half of surrogate. */
+ *ep = str;
+ return NULL;
+ }
+ /* calculate unicode codepoint from the surrogate pair */
+ uc = 0x10000 + (((uc & 0x3FF) << 10) | (uc2 & 0x3FF));
+ }
+
+ /* encode as UTF8
+ * takes at maximum 4 bytes to encode:
+ * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
+ len = 4;
+ if (uc < 0x80)
+ {
+ /* normal ascii, encoding 0xxxxxxx */
+ len = 1;
+ }
+ else if (uc < 0x800)
+ {
+ /* two bytes, encoding 110xxxxx 10xxxxxx */
+ len = 2;
+ }
+ else if (uc < 0x10000)
+ {
+ /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */
+ len = 3;
+ }
+ ptr2 += len;
+
+ switch (len) {
+ case 4:
+ /* 10xxxxxx */
+ *--ptr2 = ((uc | 0x80) & 0xBF);
+ uc >>= 6;
+ case 3:
+ /* 10xxxxxx */
+ *--ptr2 = ((uc | 0x80) & 0xBF);
+ uc >>= 6;
+ case 2:
+ /* 10xxxxxx */
+ *--ptr2 = ((uc | 0x80) & 0xBF);
+ uc >>= 6;
+ case 1:
+ /* depending on the length in bytes this determines the
+ * encoding ofthe first UTF8 byte */
+ *--ptr2 = (uc | firstByteMark[len]);
+ }
+ ptr2 += len;
+ break;
+ default:
+ *ep = str;
+ return NULL;
+ }
+ ptr++;
+ }
+ }
+ *ptr2 = '\0';
+ if (*ptr == '\"')
+ {
+ ptr++;
+ }
+
+ return ptr;
+}
+
+/* Render the cstring provided to an escaped version that can be printed. */
+static char *print_string_ptr(const char *str, printbuffer *p)
+{
+ const char *ptr = NULL;
+ char *ptr2 = NULL;
+ char *out = NULL;
+ int len = 0;
+ cjbool flag = false;
+ unsigned char token = '\0';
+
+ /* empty string */
+ if (!str)
+ {
+ if (p)
+ {
+ out = ensure(p, 3);
+ }
+ else
+ {
+ out = (char*)cJSON_malloc(3);
+ }
+ if (!out)
+ {
+ return NULL;
+ }
+ strcpy(out, "\"\"");
+
+ return out;
+ }
+
+ /* set "flag" to 1 if something needs to be escaped */
+ for (ptr = str; *ptr; ptr++)
+ {
+ flag |= (((*ptr > 0) && (*ptr < 32)) /* unprintable characters */
+ || (*ptr == '\"') /* double quote */
+ || (*ptr == '\\')) /* backslash */
+ ? 1
+ : 0;
+ }
+ /* no characters have to be escaped */
+ if (!flag)
+ {
+ len = ptr - str;
+ if (p)
+ {
+ out = ensure(p, len + 3);
+ }
+ else
+ {
+ out = (char*)cJSON_malloc(len + 3);
+ }
+ if (!out)
+ {
+ return NULL;
+ }
+
+ ptr2 = out;
+ *ptr2++ = '\"';
+ strcpy(ptr2, str);
+ ptr2[len] = '\"';
+ ptr2[len + 1] = '\0';
+
+ return out;
+ }
+
+ ptr = str;
+ /* calculate additional space that is needed for escaping */
+ while ((token = *ptr) && ++len)
+ {
+ if (strchr("\"\\\b\f\n\r\t", token))
+ {
+ len++; /* +1 for the backslash */
+ }
+ else if (token < 32)
+ {
+ len += 5; /* +5 for \uXXXX */
+ }
+ ptr++;
+ }
+
+ if (p)
+ {
+ out = ensure(p, len + 3);
+ }
+ else
+ {
+ out = (char*)cJSON_malloc(len + 3);
+ }
+ if (!out)
+ {
+ return NULL;
+ }
+
+ ptr2 = out;
+ ptr = str;
+ *ptr2++ = '\"';
+ /* copy the string */
+ while (*ptr)
+ {
+ if (((unsigned char)*ptr > 31) && (*ptr != '\"') && (*ptr != '\\'))
+ {
+ /* normal character, copy */
+ *ptr2++ = *ptr++;
+ }
+ else
+ {
+ /* character needs to be escaped */
+ *ptr2++ = '\\';
+ switch (token = *ptr++)
+ {
+ case '\\':
+ *ptr2++ = '\\';
+ break;
+ case '\"':
+ *ptr2++ = '\"';
+ break;
+ case '\b':
+ *ptr2++ = 'b';
+ break;
+ case '\f':
+ *ptr2++ = 'f';
+ break;
+ case '\n':
+ *ptr2++ = 'n';
+ break;
+ case '\r':
+ *ptr2++ = 'r';
+ break;
+ case '\t':
+ *ptr2++ = 't';
+ break;
+ default:
+ /* escape and print as unicode codepoint */
+ sprintf(ptr2, "u%04x", token);
+ ptr2 += 5;
+ break;
+ }
+ }
+ }
+ *ptr2++ = '\"';
+ *ptr2++ = '\0';
+
+ return out;
+}
+
+/* Invoke print_string_ptr (which is useful) on an item. */
+static char *print_string(const cJSON *item, printbuffer *p)
+{
+ return print_string_ptr(item->valuestring, p);
+}
+
+/* Predeclare these prototypes. */
+static const char *parse_value(cJSON *item, const char *value, const char **ep);
+static char *print_value(const cJSON *item, int depth, cjbool fmt, printbuffer *p);
+static const char *parse_array(cJSON *item, const char *value, const char **ep);
+static char *print_array(const cJSON *item, int depth, cjbool fmt, printbuffer *p);
+static const char *parse_object(cJSON *item, const char *value, const char **ep);
+static char *print_object(const cJSON *item, int depth, cjbool fmt, printbuffer *p);
+
+/* Utility to jump whitespace and cr/lf */
+static const char *skip(const char *in)
+{
+ while (in && *in && ((unsigned char)*in<=32))
+ {
+ in++;
+ }
+
+ return in;
+}
+
+/* Parse an object - create a new root, and populate. */
+cJSON *cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cjbool require_null_terminated)
+{
+ const char *end = NULL;
+ /* use global error pointer if no specific one was given */
+ const char **ep = return_parse_end ? return_parse_end : &global_ep;
+ cJSON *c = cJSON_New_Item();
+ *ep = NULL;
+ if (!c) /* memory fail */
+ {
+ return NULL;
+ }
+
+ end = parse_value(c, skip(value), ep);
+ if (!end)
+ {
+ /* parse failure. ep is set. */
+ cJSON_Delete(c);
+ return NULL;
+ }
+
+ /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
+ if (require_null_terminated)
+ {
+ end = skip(end);
+ if (*end)
+ {
+ cJSON_Delete(c);
+ *ep = end;
+ return NULL;
+ }
+ }
+ if (return_parse_end)
+ {
+ *return_parse_end = end;
+ }
+
+ return c;
+}
+
+/* Default options for cJSON_Parse */
+cJSON *cJSON_Parse(const char *value)
+{
+ return cJSON_ParseWithOpts(value, 0, 0);
+}
+
+/* Render a cJSON item/entity/structure to text. */
+char *cJSON_Print(const cJSON *item)
+{
+ return print_value(item, 0, 1, 0);
+}
+
+char *cJSON_PrintUnformatted(const cJSON *item)
+{
+ return print_value(item, 0, 0, 0);
+}
+
+char *cJSON_PrintBuffered(const cJSON *item, int prebuffer, cjbool fmt)
+{
+ printbuffer p;
+ p.buffer = (char*)cJSON_malloc(prebuffer);
+ if (!p.buffer)
+ {
+ return NULL;
+ }
+ p.length = prebuffer;
+ p.offset = 0;
+
+ return print_value(item, 0, fmt, &p);
+}
+
+
+/* Parser core - when encountering text, process appropriately. */
+static const char *parse_value(cJSON *item, const char *value, const char **ep)
+{
+ if (!value)
+ {
+ /* Fail on null. */
+ return NULL;
+ }
+
+ /* parse the different types of values */
+ if (!strncmp(value, "null", 4))
+ {
+ item->type = cJSON_NULL;
+ return value + 4;
+ }
+ if (!strncmp(value, "false", 5))
+ {
+ item->type = cJSON_False;
+ return value + 5;
+ }
+ if (!strncmp(value, "true", 4))
+ {
+ item->type = cJSON_True;
+ item->valueint = 1;
+ return value + 4;
+ }
+ if (*value == '\"')
+ {
+ return parse_string(item, value, ep);
+ }
+ if ((*value == '-') || ((*value >= '0') && (*value <= '9')))
+ {
+ return parse_number(item, value);
+ }
+ if (*value == '[')
+ {
+ return parse_array(item, value, ep);
+ }
+ if (*value == '{')
+ {
+ return parse_object(item, value, ep);
+ }
+
+ /* failure. */
+ *ep = value;
+ return NULL;
+}
+
+/* Render a value to text. */
+static char *print_value(const cJSON *item, int depth, cjbool fmt, printbuffer *p)
+{
+ char *out = NULL;
+
+ if (!item)
+ {
+ return NULL;
+ }
+ if (p)
+ {
+ switch ((item->type) & 0xFF)
+ {
+ case cJSON_NULL:
+ out = ensure(p, 5);
+ if (out)
+ {
+ strcpy(out, "null");
+ }
+ break;
+ case cJSON_False:
+ out = ensure(p, 6);
+ if (out)
+ {
+ strcpy(out, "false");
+ }
+ break;
+ case cJSON_True:
+ out = ensure(p, 5);
+ if (out)
+ {
+ strcpy(out, "true");
+ }
+ break;
+ case cJSON_Number:
+ out = print_number(item, p);
+ break;
+ case cJSON_String:
+ out = print_string(item, p);
+ break;
+ case cJSON_Array:
+ out = print_array(item, depth, fmt, p);
+ break;
+ case cJSON_Object:
+ out = print_object(item, depth, fmt, p);
+ break;
+ }
+ }
+ else
+ {
+ switch ((item->type) & 0xFF)
+ {
+ case cJSON_NULL:
+ out = cJSON_strdup("null");
+ break;
+ case cJSON_False:
+ out = cJSON_strdup("false");
+ break;
+ case cJSON_True:
+ out = cJSON_strdup("true");
+ break;
+ case cJSON_Number:
+ out = print_number(item, 0);
+ break;
+ case cJSON_String:
+ out = print_string(item, 0);
+ break;
+ case cJSON_Array:
+ out = print_array(item, depth, fmt, 0);
+ break;
+ case cJSON_Object:
+ out = print_object(item, depth, fmt, 0);
+ break;
+ }
+ }
+
+ return out;
+}
+
+/* Build an array from input text. */
+static const char *parse_array(cJSON *item,const char *value,const char **ep)
+{
+ cJSON *child = NULL;
+ if (*value != '[')
+ {
+ /* not an array! */
+ *ep = value;
+ return NULL;
+ }
+
+ item->type = cJSON_Array;
+ value = skip(value + 1);
+ if (*value == ']')
+ {
+ /* empty array. */
+ return value + 1;
+ }
+
+ item->child = child = cJSON_New_Item();
+ if (!item->child)
+ {
+ /* memory fail */
+ return NULL;
+ }
+ /* skip any spacing, get the value. */
+ value = skip(parse_value(child, skip(value), ep));
+ if (!value)
+ {
+ return NULL;
+ }
+
+ /* loop through the comma separated array elements */
+ while (*value == ',')
+ {
+ cJSON *new_item = NULL;
+ if (!(new_item = cJSON_New_Item()))
+ {
+ /* memory fail */
+ return NULL;
+ }
+ /* add new item to end of the linked list */
+ child->next = new_item;
+ new_item->prev = child;
+ child = new_item;
+
+ /* go to the next comma */
+ value = skip(parse_value(child, skip(value + 1), ep));
+ if (!value)
+ {
+ /* memory fail */
+ return NULL;
+ }
+ }
+
+ if (*value == ']')
+ {
+ /* end of array */
+ return value + 1;
+ }
+
+ /* malformed. */
+ *ep = value;
+
+ return NULL;
+}
+
+/* Render an array to text */
+static char *print_array(const cJSON *item, int depth, cjbool fmt, printbuffer *p)
+{
+ char **entries;
+ char *out = NULL;
+ char *ptr = NULL;
+ char *ret = NULL;
+ int len = 5;
+ cJSON *child = item->child;
+ int numentries = 0;
+ int i = 0;
+ cjbool fail = false;
+ size_t tmplen = 0;
+
+ /* How many entries in the array? */
+ while (child)
+ {
+ numentries++;
+ child = child->next;
+ }
+
+ /* Explicitly handle numentries == 0 */
+ if (!numentries)
+ {
+ if (p)
+ {
+ out = ensure(p, 3);
+ }
+ else
+ {
+ out = (char*)cJSON_malloc(3);
+ }
+ if (out)
+ {
+ strcpy(out,"[]");
+ }
+
+ return out;
+ }
+
+ if (p)
+ {
+ /* Compose the output array. */
+ /* opening square bracket */
+ i = p->offset;
+ ptr = ensure(p, 1);
+ if (!ptr)
+ {
+ return NULL;
+ }
+ *ptr = '[';
+ p->offset++;
+
+ child = item->child;
+ while (child && !fail)
+ {
+ print_value(child, depth + 1, fmt, p);
+ p->offset = update(p);
+ if (child->next)
+ {
+ len = fmt ? 2 : 1;
+ ptr = ensure(p, len + 1);
+ if (!ptr)
+ {
+ return NULL;
+ }
+ *ptr++ = ',';
+ if(fmt)
+ {
+ *ptr++ = ' ';
+ }
+ *ptr = '\0';
+ p->offset += len;
+ }
+ child = child->next;
+ }
+ ptr = ensure(p, 2);
+ if (!ptr)
+ {
+ return NULL;
+ }
+ *ptr++ = ']';
+ *ptr = '\0';
+ out = (p->buffer) + i;
+ }
+ else
+ {
+ /* Allocate an array to hold the pointers to all printed values */
+ entries = (char**)cJSON_malloc(numentries * sizeof(char*));
+ if (!entries)
+ {
+ return NULL;
+ }
+ memset(entries, '\0', numentries * sizeof(char*));
+
+ /* Retrieve all the results: */
+ child = item->child;
+ while (child && !fail)
+ {
+ ret = print_value(child, depth + 1, fmt, 0);
+ entries[i++] = ret;
+ if (ret)
+ {
+ len += strlen(ret) + 2 + (fmt ? 1 : 0);
+ }
+ else
+ {
+ fail = true;
+ }
+ child = child->next;
+ }
+
+ /* If we didn't fail, try to malloc the output string */
+ if (!fail)
+ {
+ out = (char*)cJSON_malloc(len);
+ }
+ /* If that fails, we fail. */
+ if (!out)
+ {
+ fail = true;
+ }
+
+ /* Handle failure. */
+ if (fail)
+ {
+ /* free all the entries in the array */
+ for (i = 0; i < numentries; i++)
+ {
+ if (entries[i])
+ {
+ cJSON_free(entries[i]);
+ }
+ }
+ cJSON_free(entries);
+ return NULL;
+ }
+
+ /* Compose the output array. */
+ *out='[';
+ ptr = out + 1;
+ *ptr = '\0';
+ for (i = 0; i < numentries; i++)
+ {
+ tmplen = strlen(entries[i]);
+ memcpy(ptr, entries[i], tmplen);
+ ptr += tmplen;
+ if (i != (numentries - 1))
+ {
+ *ptr++ = ',';
+ if(fmt)
+ {
+ *ptr++ = ' ';
+ }
+ *ptr = '\0';
+ }
+ cJSON_free(entries[i]);
+ }
+ cJSON_free(entries);
+ *ptr++ = ']';
+ *ptr++ = '\0';
+ }
+
+ return out;
+}
+
+/* Build an object from the text. */
+static const char *parse_object(cJSON *item, const char *value, const char **ep)
+{
+ cJSON *child = NULL;
+ if (*value != '{')
+ {
+ /* not an object! */
+ *ep = value;
+ return NULL;
+ }
+
+ item->type = cJSON_Object;
+ value = skip(value + 1);
+ if (*value == '}')
+ {
+ /* empty object. */
+ return value + 1;
+ }
+
+ child = cJSON_New_Item();
+ item->child = child;
+ if (!item->child)
+ {
+ return NULL;
+ }
+ /* parse first key */
+ value = skip(parse_string(child, skip(value), ep));
+ if (!value)
+ {
+ return NULL;
+ }
+ /* use string as key, not value */
+ child->string = child->valuestring;
+ child->valuestring = NULL;
+
+ if (*value != ':')
+ {
+ /* invalid object. */
+ *ep = value;
+ return NULL;
+ }
+ /* skip any spacing, get the value. */
+ value = skip(parse_value(child, skip(value + 1), ep));
+ if (!value)
+ {
+ return NULL;
+ }
+
+ while (*value == ',')
+ {
+ cJSON *new_item = NULL;
+ if (!(new_item = cJSON_New_Item()))
+ {
+ /* memory fail */
+ return NULL;
+ }
+ /* add to linked list */
+ child->next = new_item;
+ new_item->prev = child;
+
+ child = new_item;
+ value = skip(parse_string(child, skip(value + 1), ep));
+ if (!value)
+ {
+ return NULL;
+ }
+
+ /* use string as key, not value */
+ child->string = child->valuestring;
+ child->valuestring = NULL;
+
+ if (*value != ':')
+ {
+ /* invalid object. */
+ *ep = value;
+ return NULL;
+ }
+ /* skip any spacing, get the value. */
+ value = skip(parse_value(child, skip(value + 1), ep));
+ if (!value)
+ {
+ return NULL;
+ }
+ }
+ /* end of object */
+ if (*value == '}')
+ {
+ return value + 1;
+ }
+
+ /* malformed */
+ *ep = value;
+ return NULL;
+}
+
+/* Render an object to text. */
+static char *print_object(const cJSON *item, int depth, cjbool fmt, printbuffer *p)
+{
+ char **entries = NULL;
+ char **names = NULL;
+ char *out = NULL;
+ char *ptr = NULL;
+ char *ret = NULL;
+ char *str = NULL;
+ int len = 7;
+ int i = 0;
+ int j = 0;
+ cJSON *child = item->child;
+ int numentries = 0;
+ cjbool fail = false;
+ size_t tmplen = 0;
+
+ /* Count the number of entries. */
+ while (child)
+ {
+ numentries++;
+ child = child->next;
+ }
+
+ /* Explicitly handle empty object case */
+ if (!numentries)
+ {
+ if (p)
+ {
+ out = ensure(p, fmt ? depth + 4 : 3);
+ }
+ else
+ {
+ out = (char*)cJSON_malloc(fmt ? depth + 4 : 3);
+ }
+ if (!out)
+ {
+ return NULL;
+ }
+ ptr = out;
+ *ptr++ = '{';
+ if (fmt) {
+ *ptr++ = '\n';
+ for (i = 0; i < depth; i++)
+ {
+ *ptr++ = '\t';
+ }
+ }
+ *ptr++ = '}';
+ *ptr++ = '\0';
+
+ return out;
+ }
+
+ if (p)
+ {
+ /* Compose the output: */
+ i = p->offset;
+ len = fmt ? 2 : 1; /* fmt: {\n */
+ ptr = ensure(p, len + 1);
+ if (!ptr)
+ {
+ return NULL;
+ }
+
+ *ptr++ = '{';
+ if (fmt)
+ {
+ *ptr++ = '\n';
+ }
+ *ptr = '\0';
+ p->offset += len;
+
+ child = item->child;
+ depth++;
+ while (child)
+ {
+ if (fmt)
+ {
+ ptr = ensure(p, depth);
+ if (!ptr)
+ {
+ return NULL;
+ }
+ for (j = 0; j < depth; j++)
+ {
+ *ptr++ = '\t';
+ }
+ p->offset += depth;
+ }
+
+ /* print key */
+ print_string_ptr(child->string, p);
+ p->offset = update(p);
+
+ len = fmt ? 2 : 1;
+ ptr = ensure(p, len);
+ if (!ptr)
+ {
+ return NULL;
+ }
+ *ptr++ = ':';
+ if (fmt)
+ {
+ *ptr++ = '\t';
+ }
+ p->offset+=len;
+
+ /* print value */
+ print_value(child, depth, fmt, p);
+ p->offset = update(p);
+
+ /* print comma if not last */
+ len = (fmt ? 1 : 0) + (child->next ? 1 : 0);
+ ptr = ensure(p, len + 1);
+ if (!ptr)
+ {
+ return NULL;
+ }
+ if (child->next)
+ {
+ *ptr++ = ',';
+ }
+
+ if (fmt)
+ {
+ *ptr++ = '\n';
+ }
+ *ptr = '\0';
+ p->offset += len;
+
+ child = child->next;
+ }
+
+ ptr = ensure(p, fmt ? (depth + 1) : 2);
+ if (!ptr)
+ {
+ return NULL;
+ }
+ if (fmt)
+ {
+ for (i = 0; i < (depth - 1); i++)
+ {
+ *ptr++ = '\t';
+ }
+ }
+ *ptr++ = '}';
+ *ptr = '\0';
+ out = (p->buffer) + i;
+ }
+ else
+ {
+ /* Allocate space for the names and the objects */
+ entries = (char**)cJSON_malloc(numentries * sizeof(char*));
+ if (!entries)
+ {
+ return NULL;
+ }
+ names = (char**)cJSON_malloc(numentries * sizeof(char*));
+ if (!names)
+ {
+ cJSON_free(entries);
+ return NULL;
+ }
+ memset(entries, '\0', sizeof(char*) * numentries);
+ memset(names, '\0', sizeof(char*) * numentries);
+
+ /* Collect all the results into our arrays: */
+ child = item->child;
+ depth++;
+ if (fmt)
+ {
+ len += depth;
+ }
+ while (child && !fail)
+ {
+ names[i] = str = print_string_ptr(child->string, 0); /* print key */
+ entries[i++] = ret = print_value(child, depth, fmt, 0);
+ if (str && ret)
+ {
+ len += strlen(ret) + strlen(str) + 2 + (fmt ? 2 + depth : 0);
+ }
+ else
+ {
+ fail = true;
+ }
+ child = child->next;
+ }
+
+ /* Try to allocate the output string */
+ if (!fail)
+ {
+ out = (char*)cJSON_malloc(len);
+ }
+ if (!out)
+ {
+ fail = true;
+ }
+
+ /* Handle failure */
+ if (fail)
+ {
+ /* free all the printed keys and values */
+ for (i = 0; i < numentries; i++)
+ {
+ if (names[i])
+ {
+ cJSON_free(names[i]);
+ }
+ if (entries[i])
+ {
+ cJSON_free(entries[i]);
+ }
+ }
+ cJSON_free(names);
+ cJSON_free(entries);
+ return NULL;
+ }
+
+ /* Compose the output: */
+ *out = '{';
+ ptr = out + 1;
+ if (fmt)
+ {
+ *ptr++ = '\n';
+ }
+ *ptr = '\0';
+ for (i = 0; i < numentries; i++)
+ {
+ if (fmt)
+ {
+ for (j = 0; j < depth; j++)
+ {
+ *ptr++='\t';
+ }
+ }
+ tmplen = strlen(names[i]);
+ memcpy(ptr, names[i], tmplen);
+ ptr += tmplen;
+ *ptr++ = ':';
+ if (fmt)
+ {
+ *ptr++ = '\t';
+ }
+ strcpy(ptr, entries[i]);
+ ptr += strlen(entries[i]);
+ if (i != (numentries - 1))
+ {
+ *ptr++ = ',';
+ }
+ if (fmt)
+ {
+ *ptr++ = '\n';
+ }
+ *ptr = '\0';
+ cJSON_free(names[i]);
+ cJSON_free(entries[i]);
+ }
+
+ cJSON_free(names);
+ cJSON_free(entries);
+ if (fmt)
+ {
+ for (i = 0; i < (depth - 1); i++)
+ {
+ *ptr++ = '\t';
+ }
+ }
+ *ptr++ = '}';
+ *ptr++ = '\0';
+ }
+
+ return out;
+}
+
+/* Get Array size/item / object item. */
+int cJSON_GetArraySize(const cJSON *array)
+{
+ cJSON *c = array->child;
+ int i = 0;
+ while(c)
+ {
+ i++;
+ c = c->next;
+ }
+ return i;
+}
+
+cJSON *cJSON_GetArrayItem(const cJSON *array, int item)
+{
+ cJSON *c = array ? array->child : NULL;
+ while (c && item > 0)
+ {
+ item--;
+ c = c->next;
+ }
+
+ return c;
+}
+
+cJSON *cJSON_GetObjectItem(const cJSON *object, const char *string)
+{
+ cJSON *c = object ? object->child : NULL;
+ while (c && cJSON_strcasecmp(c->string, string))
+ {
+ c = c->next;
+ }
+ return c;
+}
+
+cjbool cJSON_HasObjectItem(const cJSON *object,const char *string)
+{
+ return cJSON_GetObjectItem(object, string) ? 1 : 0;
+}
+
+/* Utility for array list handling. */
+static void suffix_object(cJSON *prev, cJSON *item)
+{
+ prev->next = item;
+ item->prev = prev;
+}
+
+/* Utility for handling references. */
+static cJSON *create_reference(const cJSON *item)
+{
+ cJSON *ref = cJSON_New_Item();
+ if (!ref)
+ {
+ return NULL;
+ }
+ memcpy(ref, item, sizeof(cJSON));
+ ref->string = NULL;
+ ref->type |= cJSON_IsReference;
+ ref->next = ref->prev = NULL;
+ return ref;
+}
+
+/* Add item to array/object. */
+void cJSON_AddItemToArray(cJSON *array, cJSON *item)
+{
+ cJSON *c = array->child;
+ if (!item)
+ {
+ return;
+ }
+ if (!c)
+ {
+ /* list is empty, start new one */
+ array->child = item;
+ }
+ else
+ {
+ /* append to the end */
+ while (c->next)
+ {
+ c = c->next;
+ }
+ suffix_object(c, item);
+ }
+}
+
+void cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item)
+{
+ if (!item)
+ {
+ return;
+ }
+
+ /* free old key and set new one */
+ if (item->string)
+ {
+ cJSON_free(item->string);
+ }
+ item->string = cJSON_strdup(string);
+
+ cJSON_AddItemToArray(object,item);
+}
+
+/* Add an item to an object with constant string as key */
+void cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item)
+{
+ if (!item)
+ {
+ return;
+ }
+ if (!(item->type & cJSON_StringIsConst) && item->string)
+ {
+ cJSON_free(item->string);
+ }
+ item->string = (char*)string;
+ item->type |= cJSON_StringIsConst;
+ cJSON_AddItemToArray(object, item);
+}
+
+void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item)
+{
+ cJSON_AddItemToArray(array, create_reference(item));
+}
+
+void cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item)
+{
+ cJSON_AddItemToObject(object, string, create_reference(item));
+}
+
+cJSON *cJSON_DetachItemFromArray(cJSON *array, int which)
+{
+ cJSON *c = array->child;
+ while (c && (which > 0))
+ {
+ c = c->next;
+ which--;
+ }
+ if (!c)
+ {
+ /* item doesn't exist */
+ return NULL;
+ }
+ if (c->prev)
+ {
+ /* not the first element */
+ c->prev->next = c->next;
+ }
+ if (c->next)
+ {
+ c->next->prev = c->prev;
+ }
+ if (c==array->child)
+ {
+ array->child = c->next;
+ }
+ /* make sure the detached item doesn't point anywhere anymore */
+ c->prev = c->next = NULL;
+
+ return c;
+}
+
+void cJSON_DeleteItemFromArray(cJSON *array, int which)
+{
+ cJSON_Delete(cJSON_DetachItemFromArray(array, which));
+}
+
+cJSON *cJSON_DetachItemFromObject(cJSON *object, const char *string)
+{
+ int i = 0;
+ cJSON *c = object->child;
+ while (c && cJSON_strcasecmp(c->string,string))
+ {
+ i++;
+ c = c->next;
+ }
+ if (c)
+ {
+ return cJSON_DetachItemFromArray(object, i);
+ }
+
+ return NULL;
+}
+
+void cJSON_DeleteItemFromObject(cJSON *object, const char *string)
+{
+ cJSON_Delete(cJSON_DetachItemFromObject(object, string));
+}
+
+/* Replace array/object items with new ones. */
+void cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem)
+{
+ cJSON *c = array->child;
+ while (c && (which > 0))
+ {
+ c = c->next;
+ which--;
+ }
+ if (!c)
+ {
+ cJSON_AddItemToArray(array, newitem);
+ return;
+ }
+ newitem->next = c;
+ newitem->prev = c->prev;
+ c->prev = newitem;
+ if (c == array->child)
+ {
+ array->child = newitem;
+ }
+ else
+ {
+ newitem->prev->next = newitem;
+ }
+}
+
+void cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem)
+{
+ cJSON *c = array->child;
+ while (c && (which > 0))
+ {
+ c = c->next;
+ which--;
+ }
+ if (!c)
+ {
+ return;
+ }
+ newitem->next = c->next;
+ newitem->prev = c->prev;
+ if (newitem->next)
+ {
+ newitem->next->prev = newitem;
+ }
+ if (c == array->child)
+ {
+ array->child = newitem;
+ }
+ else
+ {
+ newitem->prev->next = newitem;
+ }
+ c->next = c->prev = NULL;
+ cJSON_Delete(c);
+}
+
+void cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem)
+{
+ int i = 0;
+ cJSON *c = object->child;
+ while(c && cJSON_strcasecmp(c->string, string))
+ {
+ i++;
+ c = c->next;
+ }
+ if(c)
+ {
+ /* free the old string if not const */
+ if (!(newitem->type & cJSON_StringIsConst) && newitem->string)
+ {
+ cJSON_free(newitem->string);
+ }
+
+ newitem->string = cJSON_strdup(string);
+ cJSON_ReplaceItemInArray(object, i, newitem);
+ }
+}
+
+/* Create basic types: */
+cJSON *cJSON_CreateNull(void)
+{
+ cJSON *item = cJSON_New_Item();
+ if(item)
+ {
+ item->type = cJSON_NULL;
+ }
+
+ return item;
+}
+
+cJSON *cJSON_CreateTrue(void)
+{
+ cJSON *item = cJSON_New_Item();
+ if(item)
+ {
+ item->type = cJSON_True;
+ }
+
+ return item;
+}
+
+cJSON *cJSON_CreateFalse(void)
+{
+ cJSON *item = cJSON_New_Item();
+ if(item)
+ {
+ item->type = cJSON_False;
+ }
+
+ return item;
+}
+
+cJSON *cJSON_CreateBool(cjbool b)
+{
+ cJSON *item = cJSON_New_Item();
+ if(item)
+ {
+ item->type = b ? cJSON_True : cJSON_False;
+ }
+
+ return item;
+}
+
+cJSON *cJSON_CreateNumber(double num)
+{
+ cJSON *item = cJSON_New_Item();
+ if(item)
+ {
+ item->type = cJSON_Number;
+ item->valuedouble = num;
+ item->valueint = (int)num;
+ }
+
+ return item;
+}
+
+cJSON *cJSON_CreateString(const char *string)
+{
+ cJSON *item = cJSON_New_Item();
+ if(item)
+ {
+ item->type = cJSON_String;
+ item->valuestring = cJSON_strdup(string);
+ if(!item->valuestring)
+ {
+ cJSON_Delete(item);
+ return NULL;
+ }
+ }
+
+ return item;
+}
+
+cJSON *cJSON_CreateArray(void)
+{
+ cJSON *item = cJSON_New_Item();
+ if(item)
+ {
+ item->type=cJSON_Array;
+ }
+
+ return item;
+}
+
+cJSON *cJSON_CreateObject(void)
+{
+ cJSON *item = cJSON_New_Item();
+ if (item)
+ {
+ item->type = cJSON_Object;
+ }
+
+ return item;
+}
+
+/* Create Arrays: */
+cJSON *cJSON_CreateIntArray(const int *numbers, int count)
+{
+ int i = 0;
+ cJSON *n = NULL;
+ cJSON *p = NULL;
+ cJSON *a = cJSON_CreateArray();
+ for(i = 0; a && (i < count); i++)
+ {
+ n = cJSON_CreateNumber(numbers[i]);
+ if (!n)
+ {
+ cJSON_Delete(a);
+ return NULL;
+ }
+ if(!i)
+ {
+ a->child = n;
+ }
+ else
+ {
+ suffix_object(p, n);
+ }
+ p = n;
+ }
+
+ return a;
+}
+
+cJSON *cJSON_CreateFloatArray(const float *numbers, int count)
+{
+ int i = 0;
+ cJSON *n = NULL;
+ cJSON *p = NULL;
+ cJSON *a = cJSON_CreateArray();
+ for(i = 0; a && (i < count); i++)
+ {
+ n = cJSON_CreateNumber(numbers[i]);
+ if(!n)
+ {
+ cJSON_Delete(a);
+ return NULL;
+ }
+ if(!i)
+ {
+ a->child = n;
+ }
+ else
+ {
+ suffix_object(p, n);
+ }
+ p = n;
+ }
+
+ return a;
+}
+
+cJSON *cJSON_CreateDoubleArray(const double *numbers, int count)
+{
+ int i = 0;
+ cJSON *n = NULL;
+ cJSON *p = NULL;
+ cJSON *a = cJSON_CreateArray();
+ for(i = 0;a && (i < count); i++)
+ {
+ n = cJSON_CreateNumber(numbers[i]);
+ if(!n)
+ {
+ cJSON_Delete(a);
+ return NULL;
+ }
+ if(!i)
+ {
+ a->child = n;
+ }
+ else
+ {
+ suffix_object(p, n);
+ }
+ p = n;
+ }
+
+ return a;
+}
+
+cJSON *cJSON_CreateStringArray(const char **strings, int count)
+{
+ int i = 0;
+ cJSON *n = NULL;
+ cJSON *p = NULL;
+ cJSON *a = cJSON_CreateArray();
+ for (i = 0; a && (i < count); i++)
+ {
+ n = cJSON_CreateString(strings[i]);
+ if(!n)
+ {
+ cJSON_Delete(a);
+ return NULL;
+ }
+ if(!i)
+ {
+ a->child = n;
+ }
+ else
+ {
+ suffix_object(p,n);
+ }
+ p = n;
+ }
+
+ return a;
+}
+
+/* Duplication */
+cJSON *cJSON_Duplicate(const cJSON *item, cjbool recurse)
+{
+ cJSON *newitem = NULL;
+ cJSON *cptr = NULL;
+ cJSON *nptr = NULL;
+ cJSON *newchild = NULL;
+
+ /* Bail on bad ptr */
+ if (!item)
+ {
+ return NULL;
+ }
+ /* Create new item */
+ newitem = cJSON_New_Item();
+ if (!newitem)
+ {
+ return NULL;
+ }
+ /* Copy over all vars */
+ newitem->type = item->type & (~cJSON_IsReference);
+ newitem->valueint = item->valueint;
+ newitem->valuedouble = item->valuedouble;
+ if (item->valuestring)
+ {
+ newitem->valuestring = cJSON_strdup(item->valuestring);
+ if (!newitem->valuestring)
+ {
+ cJSON_Delete(newitem);
+ return NULL;
+ }
+ }
+ if (item->string)
+ {
+ newitem->string = cJSON_strdup(item->string);
+ if (!newitem->string)
+ {
+ cJSON_Delete(newitem);
+ return NULL;
+ }
+ }
+ /* If non-recursive, then we're done! */
+ if (!recurse)
+ {
+ return newitem;
+ }
+ /* Walk the ->next chain for the child. */
+ cptr = item->child;
+ while (cptr)
+ {
+ newchild = cJSON_Duplicate(cptr, 1); /* Duplicate (with recurse) each item in the ->next chain */
+ if (!newchild)
+ {
+ cJSON_Delete(newitem);
+ return NULL;
+ }
+ if (nptr)
+ {
+ /* If newitem->child already set, then crosswire ->prev and ->next and move on */
+ nptr->next = newchild;
+ newchild->prev = nptr;
+ nptr = newchild;
+ }
+ else
+ {
+ /* Set newitem->child and move to it */
+ newitem->child = newchild; nptr = newchild;
+ }
+ cptr = cptr->next;
+ }
+
+ return newitem;
+}
+
+void cJSON_Minify(char *json)
+{
+ char *into = json;
+ while (*json)
+ {
+ if (*json == ' ')
+ {
+ json++;
+ }
+ else if (*json == '\t')
+ {
+ /* Whitespace characters. */
+ json++;
+ }
+ else if (*json == '\r')
+ {
+ json++;
+ }
+ else if (*json=='\n')
+ {
+ json++;
+ }
+ else if ((*json == '/') && (json[1] == '/'))
+ {
+ /* double-slash comments, to end of line. */
+ while (*json && (*json != '\n'))
+ {
+ json++;
+ }
+ }
+ else if ((*json == '/') && (json[1] == '*'))
+ {
+ /* multiline comments. */
+ while (*json && !((*json == '*') && (json[1] == '/')))
+ {
+ json++;
+ }
+ json += 2;
+ }
+ else if (*json == '\"')
+ {
+ /* string literals, which are \" sensitive. */
+ *into++ = *json++;
+ while (*json && (*json != '\"'))
+ {
+ if (*json == '\\')
+ {
+ *into++=*json++;
+ }
+ *into++ = *json++;
+ }
+ *into++ = *json++;
+ }
+ else
+ {
+ /* All other characters. */
+ *into++ = *json++;
+ }
+ }
+
+ /* and null-terminate. */
+ *into = '\0';
+}
diff --git a/service/src/cJSON.h b/service/src/cJSON.h
new file mode 100644
index 0000000..dbbb739
--- /dev/null
+++ b/service/src/cJSON.h
@@ -0,0 +1,165 @@
+/*
+ Copyright (c) 2009 Dave Gamble
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#ifndef cJSON__h
+#define cJSON__h
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stddef.h>
+
+/* cJSON Types: */
+#define cJSON_False (1 << 0)
+#define cJSON_True (1 << 1)
+#define cJSON_NULL (1 << 2)
+#define cJSON_Number (1 << 3)
+#define cJSON_String (1 << 4)
+#define cJSON_Array (1 << 5)
+#define cJSON_Object (1 << 6)
+
+#define cJSON_IsReference 256
+#define cJSON_StringIsConst 512
+
+/* The cJSON structure: */
+typedef struct cJSON
+{
+ /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
+ struct cJSON *next;
+ struct cJSON *prev;
+ /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
+ struct cJSON *child;
+
+ /* The type of the item, as above. */
+ int type;
+
+ /* The item's string, if type==cJSON_String */
+ char *valuestring;
+ /* The item's number, if type==cJSON_Number */
+ int valueint;
+ /* The item's number, if type==cJSON_Number */
+ double valuedouble;
+
+ /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
+ char *string;
+} cJSON;
+
+typedef struct cJSON_Hooks
+{
+ void *(*malloc_fn)(size_t sz);
+ void (*free_fn)(void *ptr);
+} cJSON_Hooks;
+
+/* Supply malloc, realloc and free functions to cJSON */
+extern void cJSON_InitHooks(cJSON_Hooks* hooks);
+
+
+/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */
+extern cJSON *cJSON_Parse(const char *value);
+/* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */
+extern char *cJSON_Print(const cJSON *item);
+/* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */
+extern char *cJSON_PrintUnformatted(const cJSON *item);
+/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
+extern char *cJSON_PrintBuffered(const cJSON *item, int prebuffer, int fmt);
+/* Delete a cJSON entity and all subentities. */
+extern void cJSON_Delete(cJSON *c);
+
+/* Returns the number of items in an array (or object). */
+extern int cJSON_GetArraySize(const cJSON *array);
+/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */
+extern cJSON *cJSON_GetArrayItem(const cJSON *array, int item);
+/* Get item "string" from object. Case insensitive. */
+extern cJSON *cJSON_GetObjectItem(const cJSON *object, const char *string);
+extern int cJSON_HasObjectItem(const cJSON *object, const char *string);
+/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
+extern const char *cJSON_GetErrorPtr(void);
+
+/* These calls create a cJSON item of the appropriate type. */
+extern cJSON *cJSON_CreateNull(void);
+extern cJSON *cJSON_CreateTrue(void);
+extern cJSON *cJSON_CreateFalse(void);
+extern cJSON *cJSON_CreateBool(int b);
+extern cJSON *cJSON_CreateNumber(double num);
+extern cJSON *cJSON_CreateString(const char *string);
+extern cJSON *cJSON_CreateArray(void);
+extern cJSON *cJSON_CreateObject(void);
+
+/* These utilities create an Array of count items. */
+extern cJSON *cJSON_CreateIntArray(const int *numbers, int count);
+extern cJSON *cJSON_CreateFloatArray(const float *numbers, int count);
+extern cJSON *cJSON_CreateDoubleArray(const double *numbers, int count);
+extern cJSON *cJSON_CreateStringArray(const char **strings, int count);
+
+/* Append item to the specified array/object. */
+extern void cJSON_AddItemToArray(cJSON *array, cJSON *item);
+extern void cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
+extern void cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item); /* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object */
+/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
+extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
+extern void cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
+
+/* Remove/Detatch items from Arrays/Objects. */
+extern cJSON *cJSON_DetachItemFromArray(cJSON *array, int which);
+extern void cJSON_DeleteItemFromArray(cJSON *array, int which);
+extern cJSON *cJSON_DetachItemFromObject(cJSON *object, const char *string);
+extern void cJSON_DeleteItemFromObject(cJSON *object, const char *string);
+
+/* Update array items. */
+extern void cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
+extern void cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
+extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
+
+/* Duplicate a cJSON item */
+extern cJSON *cJSON_Duplicate(const cJSON *item, int recurse);
+/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
+need to be released. With recurse!=0, it will duplicate any children connected to the item.
+The item->next and ->prev pointers are always zero on return from Duplicate. */
+
+/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
+/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error. If not, then cJSON_GetErrorPtr() does the job. */
+extern cJSON *cJSON_ParseWithOpts(const char *value, const char **return_parse_end, int require_null_terminated);
+
+extern void cJSON_Minify(char *json);
+
+/* Macros for creating things quickly. */
+#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull())
+#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue())
+#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse())
+#define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b))
+#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
+#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s))
+
+/* When assigning an integer value, it needs to be propagated to valuedouble too. */
+#define cJSON_SetIntValue(object,val) ((object) ? (object)->valueint = (object)->valuedouble = (val) : (val))
+#define cJSON_SetNumberValue(object,val) ((object) ? (object)->valueint = (object)->valuedouble = (val) : (val))
+
+/* Macro for iterating over an array */
+#define cJSON_ArrayForEach(pos, head) for(pos = (head)->child; pos != NULL; pos = pos->next)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/service/src/config.c b/service/src/config.c
index b404f04..2324f46 100644
--- a/service/src/config.c
+++ b/service/src/config.c
@@ -13,6 +13,7 @@
#include <mr_mask.h>
#include <mr_runtime.h>
#include <arpa/inet.h>
+#include "mr_buffer.h"
#ifndef MR_SERVICE_DEFAULT_SZ_BUFFER
#define MR_SERVICE_DEFAULT_SZ_BUFFER 32
@@ -91,6 +92,55 @@ static int __parser_str_core(char * str_core, int sz_buffer,
return 0;
}
+
+void __ctrlzone_list_join(struct sc_instance * instance, const char * ctrlzone,
+ unsigned int ctrlzone_id, unsigned int sz_ctrlzone)
+{
+ struct sc_ctrlzone * sc_ctrlzone = rte_zmalloc(NULL, sizeof(sc_ctrlzone), 0);
+ MR_CHECK(sc_ctrlzone != NULL, "Cannot alloc memory for sc_ctrlzone");
+
+ snprintf(sc_ctrlzone->symbol, sizeof(sc_ctrlzone->symbol), "%s", ctrlzone);
+ sc_ctrlzone->id = ctrlzone_id;
+ sc_ctrlzone->size = sz_ctrlzone;
+
+ TAILQ_INSERT_TAIL(&instance->ctrlzone_list, sc_ctrlzone, next);
+ return;
+}
+
+int sc_config_ctrlzone(const char * cfg, struct sc_instance * instance)
+{
+ char str_ctrlzone_key[MR_SYMBOL_MAX];
+ char str_ctrlzone_info[MR_STRING_MAX];
+ char str_ctrlzone_name[MR_STRING_MAX];
+ int sz_ctrlzone = 0;
+ int ret = 0;
+
+ for(int ctrlzone_id = 0; ctrlzone_id < MRB_MAX_CTRLZONE_NUM; ctrlzone_id++)
+ {
+ snprintf(str_ctrlzone_key, sizeof(str_ctrlzone_key), "ctrlzone%d", ctrlzone_id);
+ ret = MESA_load_profile_string_nodef(cfg, "ctrlzone", str_ctrlzone_key,
+ str_ctrlzone_info, sizeof(str_ctrlzone_info));
+ if (ret < 0) continue;
+
+ char * tokens[MR_TOKENS_MAX];
+ ret = rte_strsplit(str_ctrlzone_info, sizeof(str_ctrlzone_info), tokens,
+ MR_TOKENS_MAX, ',');
+
+ if (ret != 2)
+ return __errlog_invaild_format("LoadCtrlZone", "ctrlzone", str_ctrlzone_key);
+
+ snprintf(str_ctrlzone_name, sizeof(str_ctrlzone_name), "%s", tokens[0]);
+ sz_ctrlzone = __parser_uint(tokens[1]);
+
+ if(sz_ctrlzone < 0)
+ return __errlog_invaild_format("LoadCtrlZone", "ctrlzone", str_ctrlzone_key);
+
+ __ctrlzone_list_join(instance, str_ctrlzone_name, ctrlzone_id, sz_ctrlzone);
+ }
+
+ return 0;
+}
+
int sc_config_thread_info(const char * cfg, struct sc_instance * instance)
{
char str_thread_info[MR_STRING_MAX];
@@ -338,6 +388,8 @@ void sc_stage_config(struct sc_instance * instance)
"Please check configure file %s, Failed. ", cfgfile);
MR_CHECK(sc_config_stack_info(cfgfile, instance) >= 0,
"Please check configure file %s, Failed. ", cfgfile);
-
+ MR_CHECK(sc_config_ctrlzone(cfgfile, instance) >= 0,
+ "Please check configure file %s, Failed. ", cfgfile);
+
return;
} \ No newline at end of file
diff --git a/service/src/core.c b/service/src/core.c
index 5f62cea..f477ec2 100644
--- a/service/src/core.c
+++ b/service/src/core.c
@@ -31,16 +31,20 @@ const char service_git_version[] = "";
#define MR_SERVICE_MAX_EAL_ARGC 512
#endif
+#ifndef MR_SERVICE_DEFAULT_MONIT_FILE
+#define MR_SERVICE_DEFAULT_MONIT_FILE "/tmp/.mrzcpd.moint"
+#endif
+
#ifndef MR_SERVICE_DEFAULT_GLOB_CFG
-#define MR_SERVICE_GLOB_CFG "/etc/mrglobal.conf"
+#define MR_SERVICE_DEFAULT_GLOB_CFG "/etc/mrglobal.conf"
#endif
#ifndef MR_SERVICE_DEFAULT_PROCSYM
-#define MR_SERVICE_DEFAULT_PROCSYM "serv"
+#define MR_SERVICE_DEFAULT_PROCSYM "serv"
#endif
#ifndef MR_LOGREADER_DEFAULT_PROCSYM
-#define MR_LOGREADER_DEFAULT_PROCSYM "logreader"
+#define MR_LOGREADER_DEFAULT_PROCSYM "logreader"
#endif
extern void * sc_runtime_thread(void * args);
@@ -150,6 +154,14 @@ struct sc_instance * sc_instance_new()
return instance;
}
+void sc_instance_init_monitfile(struct sc_instance * instance)
+{
+ snprintf(instance->local_monitfile, sizeof(instance->local_monitfile), "%s",
+ MR_SERVICE_DEFAULT_MONIT_FILE);
+ return;
+}
+
+
void sc_instance_init_log(struct sc_instance * instance)
{
// 如果没有设置,使用默认的日志流(到屏幕上)
@@ -177,7 +189,7 @@ void sc_instance_init_cfg(struct sc_instance * instance)
default_cfgfile:
snprintf(instance->local_cfgfile, sizeof(instance->local_logfile), "%s",
- MR_SERVICE_GLOB_CFG);
+ MR_SERVICE_DEFAULT_GLOB_CFG);
MR_LOG(INFO, SERVICE, "Global Configure File: %s\n", instance->local_cfgfile);
}
@@ -190,11 +202,19 @@ void sc_instance_init_progsym(struct sc_instance * instance)
return;
}
+void sc_instance_init_ctrlzone_list(struct sc_instance * instance)
+{
+ TAILQ_INIT(&instance->ctrlzone_list);
+ return;
+}
+
void sc_instance_init(struct sc_instance * instance)
{
sc_instance_init_log(instance);
sc_instance_init_cfg(instance);
+ sc_instance_init_monitfile(instance);
sc_instance_init_progsym(instance);
+ sc_instance_init_ctrlzone_list(instance);
}
void sc_instance_ctx_init(struct sc_instance * instance)
@@ -209,11 +229,29 @@ void sc_stage_init(struct sc_instance * instance)
return;
}
+extern int sc_monit_loop(struct sc_instance * sc_instance);
+
+void * sc_loop_thread(void * args)
+{
+ struct sc_instance * instance = (struct sc_instance *)args;
+ pthread_detach(pthread_self());
+
+ while(1)
+ {
+ sc_monit_loop(instance);
+ sleep(1);
+ }
+}
+
+
void sc_launch_thread(struct sc_instance * instance)
{
int nr_thread = mask_popcnt(instance->cpu_mask);
MR_CHECK(nr_thread >= 0, "Invailed CPU Mask");
-
+
+ pthread_t pid_loop;
+ pthread_create(&pid_loop, NULL, sc_loop_thread, instance);
+
pthread_t * pids = (pthread_t *)malloc(sizeof(pthread_t) * nr_thread);
MR_CHECK(pids != NULL, "Cannot alloc memory for pthread_t structures");
diff --git a/service/src/monit.c b/service/src/monit.c
new file mode 100644
index 0000000..14489c3
--- /dev/null
+++ b/service/src/monit.c
@@ -0,0 +1,107 @@
+/* \brief ״̬����������
+ *
+ * \author Lu Qiuwen<[email protected]>
+ * \date 2016-11-30
+ */
+
+#include <sc_common.h>
+#include <mr_device.h>
+#include <rte_ethdev.h>
+#include <rte_pci.h>
+
+#include "cJSON.h"
+
+// ��������ͳ�Ƽ���
+static cJSON * __create_device_stats(struct mr_dev * dev)
+{
+ struct cJSON * j_device_stats = cJSON_CreateObject();
+ struct rte_eth_stats _eth_stat;
+ rte_eth_stats_get(dev->port_id, &_eth_stat);
+
+ cJSON_AddNumberToObject(j_device_stats, "ipackets", _eth_stat.ipackets);
+ cJSON_AddNumberToObject(j_device_stats, "opackets", _eth_stat.opackets);
+ cJSON_AddNumberToObject(j_device_stats, "ibytes", _eth_stat.ibytes);
+ cJSON_AddNumberToObject(j_device_stats, "obytes", _eth_stat.obytes);
+ cJSON_AddNumberToObject(j_device_stats, "imissed", _eth_stat.imissed);
+ cJSON_AddNumberToObject(j_device_stats, "ierrors", _eth_stat.ierrors);
+ cJSON_AddNumberToObject(j_device_stats, "oerrors", _eth_stat.oerrors);
+ cJSON_AddNumberToObject(j_device_stats, "rxnombuf", _eth_stat.rx_nombuf);
+ return j_device_stats;
+}
+
+// ����������·��Ϣ���
+static cJSON * __create_device_link(struct mr_dev * dev)
+{
+ struct cJSON * j_device_link = cJSON_CreateObject();
+ struct rte_eth_link _eth_link;
+
+ rte_eth_link_get_nowait(dev->port_id, &_eth_link);
+ cJSON_AddNumberToObject(j_device_link, "LinkSpeed", _eth_link.link_speed);
+ cJSON_AddBoolToObject(j_device_link, "LinkDuplex", _eth_link.link_duplex);
+ cJSON_AddBoolToObject(j_device_link, "LinkAutoNeg", _eth_link.link_autoneg);
+ cJSON_AddBoolToObject(j_device_link, "LinkStatus", _eth_link.link_status);
+ return j_device_link;
+}
+
+// ��������������Ϣ���
+static cJSON * __create_device_info(struct mr_dev * dev)
+{
+ struct cJSON * j_device_info = cJSON_CreateObject();
+
+ char str_ether_addr[MR_STRING_MAX];
+ ether_format_addr(str_ether_addr, sizeof(str_ether_addr), &dev->ether_addr);
+
+ struct rte_pci_addr * pci_addr = &dev->info.pci_addr;
+ char str_pci_addr[MR_STRING_MAX];
+ snprintf(str_pci_addr, sizeof(str_pci_addr), PCI_PRI_FMT, pci_addr->bus,
+ pci_addr->devid, pci_addr->domain, pci_addr->function);
+
+ cJSON_AddStringToObject(j_device_info, "EtherAddr", str_ether_addr);
+ cJSON_AddStringToObject(j_device_info, "PCIAddr", str_pci_addr);
+ cJSON_AddNumberToObject(j_device_info, "PortID", dev->port_id);
+ cJSON_AddNumberToObject(j_device_info, "RxQueueCount", dev->nr_rxq);
+ cJSON_AddNumberToObject(j_device_info, "TxQueueCount", dev->nr_txq);
+ cJSON_AddNumberToObject(j_device_info, "MTU", dev->mtu);
+
+ return j_device_info;
+}
+
+// ���������豸���
+static cJSON * monit_device_info(struct sc_instance * sc_instance)
+{
+ struct cJSON * j_device_array = cJSON_CreateArray();
+
+ int nr_devices = 0;
+ struct mr_dev * mr_dev_info[MR_DEVICE_MAX];
+ nr_devices = mr_device_list(sc_instance->core_instance, mr_dev_info, MR_DEVICE_MAX, 0);
+
+ for(int i = 0; i < nr_devices; i++)
+ {
+ struct cJSON * j_device = cJSON_CreateObject();
+ cJSON_AddStringToObject(j_device, "symbol", mr_dev_info[i]->symbol);
+ cJSON_AddItemToObject(j_device, "information", __create_device_info(mr_dev_info[i]));
+ cJSON_AddItemToObject(j_device, "link", __create_device_link(mr_dev_info[i]));
+ cJSON_AddItemToObject(j_device, "stats", __create_device_stats(mr_dev_info[i]));
+ cJSON_AddItemToArray(j_device_array, j_device);
+ }
+
+ return j_device_array;
+}
+
+static cJSON * monit_root(struct sc_instance * sc_instance)
+{
+ struct cJSON * j_root = cJSON_CreateObject();
+ cJSON_AddItemToObject(j_root, "device", monit_device_info(sc_instance));
+ return j_root;
+}
+
+int sc_monit_loop(struct sc_instance * sc_instance)
+{
+ FILE * fp_monit = fopen(sc_instance->local_monitfile, "w");
+ cJSON * j_root = monit_root(sc_instance);
+ char * str_json_print = cJSON_Print(j_root);
+ fprintf(fp_monit, "%s", str_json_print);
+ free(j_root);
+ fclose(fp_monit);
+ return 0;
+} \ No newline at end of file
diff --git a/service/src/register.c b/service/src/register.c
index a0c158d..57b66d4 100644
--- a/service/src/register.c
+++ b/service/src/register.c
@@ -44,36 +44,23 @@ static int sc_core_instance_register(struct sc_instance * instance)
static int sc_core_ctrlzone_register(struct sc_instance * instance)
{
- for(int i = 0; i < MRB_MAX_CTRLZONE_NUM; i++)
+ struct sc_ctrlzone * ctrlzone_iter;
+ TAILQ_FOREACH(ctrlzone_iter, &instance->ctrlzone_list, next)
{
- char str_ctrlzone_info[MR_STRING_MAX];
- char str_ctrlzone_key[MR_SYMBOL_MAX];
- snprintf(str_ctrlzone_key, sizeof(str_ctrlzone_key), "ctrlzone%d", i);
-
- if (MESA_load_profile_string_nodef(instance->local_logfile, "ctrlzone",
- str_ctrlzone_key, str_ctrlzone_info, sizeof(str_ctrlzone_info)) < 0) continue;
-
-
+ int ret = mr_buffer_ctrlzone_register(instance->core_instance,
+ ctrlzone_iter->symbol, ctrlzone_iter->id, ctrlzone_iter->size);
+
+ if(ret < 0)
+ {
+ MR_LOG(ERR, SERVICE, "Register ctrlzone %s(size=%d, id=%d) failed. ",
+ ctrlzone_iter->symbol, ctrlzone_iter->size, ctrlzone_iter->id);
+ return -1;
+ }
+
+ MR_LOG(INFO, SERVICE, "Register ctrlzone %s(size=%d, id=%d) successfully. \n",
+ ctrlzone_iter->symbol, ctrlzone_iter->size, ctrlzone_iter->id);
}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
return 0;
}
@@ -269,6 +256,8 @@ void sc_stage_register(struct sc_instance * instance)
{
MR_CHECK(sc_core_instance_register(instance) >= 0,
"Cannot register core instance, Failed. Please recheck runtime log. ");
+ MR_CHECK(sc_core_ctrlzone_register(instance) >= 0,
+ "Cannot register control zone, Failed. Please recheck runtime log.");
MR_CHECK(sc_stack_instance_register(instance) >= 0,
"Cannot register stack instance, Failed. Please recheck runtime log. ");
MR_CHECK(sc_app_register(instance) >= 0,