diff options
| -rw-r--r-- | app/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | app/include/mrapp.h | 18 | ||||
| -rw-r--r-- | app/src/cJSON.c | 2233 | ||||
| -rw-r--r-- | app/src/cJSON.h | 165 | ||||
| -rw-r--r-- | app/src/marsio.c | 19 | ||||
| -rw-r--r-- | app/src/monit.c | 98 | ||||
| -rw-r--r-- | app/src/rawio.c | 15 | ||||
| -rw-r--r-- | core/include/mr_rtdev.h | 3 | ||||
| -rw-r--r-- | core/src/rtdev.c | 28 | ||||
| -rw-r--r-- | runtime/src/app.c | 11 | ||||
| -rw-r--r-- | service/src/core.c | 2 | ||||
| -rw-r--r-- | stack/src/device.c | 5 |
12 files changed, 2575 insertions, 24 deletions
diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index ab00f78..97dae44 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -6,7 +6,7 @@ include_directories(${DPDK_INCLUDE_DIR}) include_directories(include)
add_definitions(${DPDK_C_PREDEFINED})
-add_library(marsio SHARED src/marsio.c src/rawio.c)
+add_library(marsio SHARED src/cJSON.c src/marsio.c src/rawio.c src/monit.c)
set_target_properties(marsio PROPERTIES VERSION ${MARSIO_VERSION_MAJOR}.${MARSIO_VERSION_MINOR})
set_target_properties(marsio PROPERTIES SOVERSION ${MARSIO_VERSION_MAJOR})
diff --git a/app/include/mrapp.h b/app/include/mrapp.h index 60134ea..a72a87e 100644 --- a/app/include/mrapp.h +++ b/app/include/mrapp.h @@ -36,6 +36,8 @@ struct mrapp_instance { /* Ӧ������ */ char appsym[MR_SYMBOL_MAX]; + /* ״̬������·�� */ + char monit_file_path[MR_STRING_MAX]; /* ���в��� */ struct mrapp_config config; /* Coreȫ�־�� */ @@ -46,7 +48,21 @@ struct mrapp_instance struct raw_socket * raw_socket[MR_DEVICE_MAX]; }; +struct raw_socket +{ + // �豸������ + char devsym[MR_SYMBOL_MAX]; + // Raw�ӿڶ������߳��� + unsigned int nr_rxstream; + // Raw�ӿ�д�����߳��� + unsigned int nr_txstream; + // Raw�ӿھ�� + struct rtdev_app_desc * rtdev_desc; +}; + /* ��־λ���Ƿ��Ѿ������˳�ʼ��*/ extern int mrapp_inited; /* ��־λ�����߳��Ƿ��Ѿ������˳�ʼ�� */ -extern int __thread mrapp_thread_inited;
\ No newline at end of file +extern int __thread mrapp_thread_inited; +/* ״̬������ */ +int mrapp_monit_loop(struct mrapp_instance * instance);
\ No newline at end of file diff --git a/app/src/cJSON.c b/app/src/cJSON.c new file mode 100644 index 0000000..766e558 --- /dev/null +++ b/app/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/app/src/cJSON.h b/app/src/cJSON.h new file mode 100644 index 0000000..dbbb739 --- /dev/null +++ b/app/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/app/src/marsio.c b/app/src/marsio.c index 7ee1e43..3c3a875 100644 --- a/app/src/marsio.c +++ b/app/src/marsio.c @@ -61,12 +61,17 @@ static void mrapp_eal_init(struct mrapp_config * config) return; } +#define MRAPP_MONIT_FILE_PATH "/tmp/.mrmonit.app.%s" + struct mrapp_instance * mrapp_instance_create(const char * appsym, struct mrapp_config * config) { struct mrapp_instance * _instance = rte_zmalloc(NULL, sizeof(struct mrapp_instance), 0); MR_CHECK(_instance != NULL, "Cannot alloc memory for mrapp instance"); snprintf(_instance->appsym, sizeof(instance->appsym), "%s", appsym); + snprintf(_instance->monit_file_path, sizeof(_instance->monit_file_path), + MRAPP_MONIT_FILE_PATH, _instance->appsym); + _instance->config = *config; return _instance; } @@ -133,6 +138,18 @@ static int mrapp_config_check(const char * appsym, struct mrapp_config * config) return 0; } +void * mrapp_loop_thread(void * args) +{ + struct mrapp_instance * _instance = (struct mrapp_instance *)args; + pthread_detach(pthread_self()); + + while (1) + { + mrapp_monit_loop(_instance); + sleep(1); + } +} + static int mrapp_init(const char * appsym, struct mrapp_config * config) { // У����� @@ -186,6 +203,8 @@ static int mrapp_init(const char * appsym, struct mrapp_config * config) return ret; } + pthread_t pid_loop; + pthread_create(&pid_loop, NULL, mrapp_loop_thread, instance); return 0; } diff --git a/app/src/monit.c b/app/src/monit.c new file mode 100644 index 0000000..9361440 --- /dev/null +++ b/app/src/monit.c @@ -0,0 +1,98 @@ +/* \brief Ӧ��״̬����������
+*
+* \author Lu Qiuwen<[email protected]>
+* \date 2016-11-30
+*/
+
+#include <mr_common.h>
+#include <mr_rtdev.h>
+#include <mrapp.h>
+
+#include "cJSON.h"
+
+static cJSON * __create_uint64_array(const uint64_t * value, int nr_value)
+{
+ struct cJSON * uint64_array = cJSON_CreateArray();
+ for (int i = 0; i < nr_value; i++)
+ cJSON_AddItemToArray(uint64_array, cJSON_CreateNumber(value[i]));
+ return uint64_array;
+}
+
+static cJSON * __create_raw_device_stats(struct rtdev_app_desc * dev_desc)
+{
+ struct rtdev_stat_info _stat_info;
+ mr_rtdev_app_stats_get(dev_desc, &_stat_info);
+
+ struct cJSON * j_raw_device_stats = cJSON_CreateObject();
+ unsigned int nr_rx_stream = dev_desc->nr_rx_stream;
+ unsigned int nr_tx_stream = dev_desc->nr_tx_stream;
+
+#define __JOIN_RAW_DEVICE_STATS_ITEM(item, streams) do { \
+ cJSON_AddItemToObject(j_raw_device_stats, #item, \
+ __create_uint64_array(_stat_info.item, streams)); \
+} while(0)
+
+ __JOIN_RAW_DEVICE_STATS_ITEM(rx_on_line, nr_rx_stream);
+ __JOIN_RAW_DEVICE_STATS_ITEM(rx_deliver, nr_rx_stream);
+ __JOIN_RAW_DEVICE_STATS_ITEM(rx_missed, nr_rx_stream);
+ __JOIN_RAW_DEVICE_STATS_ITEM(tx_on_line, nr_tx_stream);
+ __JOIN_RAW_DEVICE_STATS_ITEM(tx_deliver, nr_tx_stream);
+ __JOIN_RAW_DEVICE_STATS_ITEM(tx_missed, nr_tx_stream);
+ __JOIN_RAW_DEVICE_STATS_ITEM(ftx_on_line, nr_tx_stream);
+ __JOIN_RAW_DEVICE_STATS_ITEM(ftx_deliver, nr_tx_stream);
+ __JOIN_RAW_DEVICE_STATS_ITEM(ftx_missed, nr_tx_stream);
+ return j_raw_device_stats;
+}
+
+// ����ʱԭʼ�����豸ͳ�Ƽ���
+static cJSON * monit_raw_device(struct mrapp_instance * instance)
+{
+ struct cJSON * j_raw_device_array = cJSON_CreateArray();
+ for(int i = 0; i < RTE_DIM(instance->raw_socket); i++)
+ {
+ struct raw_socket * socket = instance->raw_socket[i];
+ if (socket == NULL) continue;
+
+ cJSON * j_raw_device = cJSON_CreateObject();
+ cJSON_AddStringToObject(j_raw_device, "symbol", socket->devsym);
+ cJSON_AddNumberToObject(j_raw_device, "rxstreams", socket->nr_rxstream);
+ cJSON_AddNumberToObject(j_raw_device, "txstreams", socket->nr_txstream);
+ cJSON_AddItemToObject(j_raw_device, "stats", __create_raw_device_stats(socket->rtdev_desc));
+ cJSON_AddItemToArray(j_raw_device_array, j_raw_device);
+ }
+
+ return j_raw_device_array;
+}
+
+static cJSON * monit_app_info(struct mrapp_instance * instance)
+{
+ struct cJSON * j_root = cJSON_CreateObject();
+ cJSON_AddStringToObject(j_root, "symbol", instance->appsym);
+ return j_root;
+}
+
+static cJSON * monit_root(struct mrapp_instance * instance)
+{
+ struct cJSON * j_root = cJSON_CreateObject();
+ cJSON_AddItemToObject(j_root, "appinfo", monit_app_info(instance));
+ cJSON_AddItemToObject(j_root, "raw", monit_raw_device(instance));
+ return j_root;
+}
+
+int mrapp_monit_loop(struct mrapp_instance * instance)
+{
+ FILE * fp_monit = fopen(instance->monit_file_path, "w");
+ if(fp_monit == NULL)
+ {
+ MR_LOG(INFO, MRLIB, "Open monit result file %s failed: %s \n",
+ instance->monit_file_path, strerror(errno));
+ return 0;
+ }
+
+ cJSON * j_root = monit_root(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/app/src/rawio.c b/app/src/rawio.c index 5328627..86552bd 100644 --- a/app/src/rawio.c +++ b/app/src/rawio.c @@ -14,22 +14,7 @@ extern struct mrapp_instance * instance; extern int __option_set_raw_device(struct mrapp_config * config, const char * devsym); extern int __option_set_stack_device(struct mrapp_config * config, const char * devsym); -struct raw_socket -{ - // ������ - TAILQ_ENTRY(__raw_socket) next; - // �豸������ - char devsym[MR_SYMBOL_MAX]; - // Raw�ӿڶ������߳��� - unsigned int nr_rxstream; - // Raw�ӿ�д�����߳��� - unsigned int nr_txstream; - // Raw�ӿھ�� - struct rtdev_app_desc * rtdev_desc; -}; - // ��Socket��¼����ɾ����������Ѿ���Socket��¼�����������û��ظ�����ɴ��� - int raw_socket_close(struct raw_socket * socket) { struct raw_socket * _socket = (struct raw_socket *)socket; diff --git a/core/include/mr_rtdev.h b/core/include/mr_rtdev.h index f70cd32..bd08a26 100644 --- a/core/include/mr_rtdev.h +++ b/core/include/mr_rtdev.h @@ -87,4 +87,5 @@ struct rtdev_app_desc * mr_rt_device_open(struct mr_core_instance * instance, co int mr_rt_device_close(struct rtdev_app_desc * desc); // ����ʱ�豸��Ϣͳ�� -int mr_rtdev_stats_get(struct rtdev_desc * dev_desc, struct rtdev_stat_info * stat_info);
\ No newline at end of file +int mr_rtdev_stats_get(struct rtdev_desc * dev_desc, struct rtdev_stat_info * stat_info); +int mr_rtdev_app_stats_get(struct rtdev_app_desc * app_desc, struct rtdev_stat_info * stat_info);
\ No newline at end of file diff --git a/core/src/rtdev.c b/core/src/rtdev.c index be008e6..d7cd139 100644 --- a/core/src/rtdev.c +++ b/core/src/rtdev.c @@ -76,6 +76,34 @@ struct rtdev_app_desc * mr_rtdev_app_lookup(struct rtdev_desc * dev_desc, const return __rtdev_app_lookup_unsafe(dev_desc, appsym); } +int mr_rtdev_app_stats_get(struct rtdev_app_desc * app_desc, struct rtdev_stat_info * stat_info) +{ + struct vnode_cons_stat * st_cons_rx = vnode_cons_stat_get(app_desc->vnode_cons_rx); + struct vnode_prod_stat * st_prod_tx = vnode_prod_stat_get(app_desc->vnode_prod_tx); + struct vnode_prod_stat * st_prod_ftx = vnode_prod_stat_get(app_desc->vnode_prod_ftx); + + for(int i = 0; i < app_desc->nr_rx_stream; i++) + { + stat_info->rx_on_line[i] = rte_atomic64_read(&st_cons_rx[i].on_line); + stat_info->rx_deliver[i] = rte_atomic64_read(&st_cons_rx[i].recieved); + stat_info->rx_missed[i] = rte_atomic64_read(&st_cons_rx[i].missed); + } + + for (int i = 0; i < app_desc->nr_tx_stream; i++) + { + stat_info->tx_on_line[i] = rte_atomic64_read(&st_prod_tx[i].on_line); + stat_info->tx_deliver[i] = rte_atomic64_read(&st_prod_tx[i].sent); + stat_info->tx_missed[i] = rte_atomic64_read(&st_prod_tx[i].missed); + + stat_info->ftx_on_line[i] = rte_atomic64_read(&st_prod_ftx[i].on_line); + stat_info->ftx_deliver[i] = rte_atomic64_read(&st_prod_ftx[i].sent); + stat_info->ftx_missed[i] = rte_atomic64_read(&st_prod_ftx[i].missed); + } + + return 0; +} + + int mr_rtdev_stats_get(struct rtdev_desc * dev_desc, struct rtdev_stat_info * stat_info) { struct vnode_prod_stat * st_prod_rx = vnode_prod_stat_get(dev_desc->vnode_prod_rx); diff --git a/runtime/src/app.c b/runtime/src/app.c index e598966..f7e2ac3 100644 --- a/runtime/src/app.c +++ b/runtime/src/app.c @@ -279,10 +279,14 @@ struct thread_info * __thread_lookup_unsafe(struct appinfo * pinfo, thread_id_t return NULL; } -int __set_affinity(cpu_mask_t mask) +int __set_affinity(unsigned int cpu_id) { + cpu_set_t _cpu_set; + CPU_ZERO(&_cpu_set); + CPU_SET(cpu_id, &_cpu_set); + pthread_t ppid = pthread_self(); - int ret = pthread_setaffinity_np(ppid, sizeof(cpu_mask_t), (cpu_set_t *)&mask); + int ret = pthread_setaffinity_np(ppid, sizeof(cpu_mask_t), &_cpu_set); return ret; } @@ -312,8 +316,7 @@ int __thread_set_affinity(struct appinfo * pinfo, socket_id_t socket_id = mr_hwinfo_socket_id(cpu_id); assert(socket_id >= 0 && socket_id < mr_hwinfo_nr_sockets()); - cpu_mask_t thread_cpu_mask = 1L << cpu_id; - if(__set_affinity(thread_cpu_mask) < 0) + if(__set_affinity(cpu_id) != 0) { MR_LOG(INFO, BASE, "AppInfo, ThreadSetAffinity, " "Thread %d in Process %s, Call Pthread Error : %s\n", diff --git a/service/src/core.c b/service/src/core.c index f477ec2..8572a8a 100644 --- a/service/src/core.c +++ b/service/src/core.c @@ -32,7 +32,7 @@ const char service_git_version[] = ""; #endif #ifndef MR_SERVICE_DEFAULT_MONIT_FILE -#define MR_SERVICE_DEFAULT_MONIT_FILE "/tmp/.mrzcpd.moint" +#define MR_SERVICE_DEFAULT_MONIT_FILE "/tmp/.mrmonit.daemon" #endif #ifndef MR_SERVICE_DEFAULT_GLOB_CFG diff --git a/stack/src/device.c b/stack/src/device.c index e219b0c..059727a 100644 --- a/stack/src/device.c +++ b/stack/src/device.c @@ -112,8 +112,11 @@ err_out: // 创建一个协议栈设备 int sk_device_create(struct sk_instance* instance, struct sk_dev_param* param) { + int ret = 0; + // 检查设备是否已经存在,不允许重复创建 struct sk_dev_info * dev_info = sk_device_lookup(instance, param->symbol); + if(dev_info != NULL) { MR_LOG(INFO, STACK, "StackCreateDevice, StackDevice %s has been created. failed. \n", @@ -139,7 +142,7 @@ int sk_device_create(struct sk_instance* instance, struct sk_dev_param* param) dev_info->mtu = param->mtu; dev_info->promisc = 0; - int ret = route_tbl_insert(instance->default_route, dev_info->in_addr, + ret = route_tbl_insert(instance->default_route, dev_info->in_addr, dev_info->in_mask, dev_info); if (unlikely(ret < 0)) goto err_out; |
