Import app manager, samples and test-tools

This commit is contained in:
wenyongh
2019-05-17 17:15:25 +08:00
parent b6e29e2153
commit dd5b133fa5
164 changed files with 21123 additions and 496 deletions

View File

@ -0,0 +1,71 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
cmake_minimum_required (VERSION 2.8.3)
project (host-agent)
if (NOT CMAKE_BUILD_TYPE)
SET(CMAKE_BUILD_TYPE Debug)
endif (NOT CMAKE_BUILD_TYPE)
if (NOT TARGET_PLATFORM)
set (TARGET_PLATFORM "linux")
endif (NOT TARGET_PLATFORM)
message ("TARGET_PLATFORM = " ${TARGET_PLATFORM})
set(REPO_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..)
set(WASM_DIR ${REPO_ROOT_DIR}/core/iwasm)
set(APP_MGR_DIR ${REPO_ROOT_DIR}/core/app-mgr)
set(SHARED_DIR ${REPO_ROOT_DIR}/core/shared-lib)
#TODO: use soft-plc/tools/iec-runtime/external/cJSON instead
set(CJSON_DIR ${CMAKE_CURRENT_LIST_DIR}/external/cJSON)
set(SSG_LIB_DIR ${REPO_ROOT_DIR}/../host-agent/lib)
include (${WASM_DIR}/lib/native-interface/native_interface.cmake)
include (${APP_MGR_DIR}/app-mgr-shared/app_mgr_shared.cmake)
include (${SHARED_DIR}/platform/${TARGET_PLATFORM}/shared_platform.cmake)
include (${SHARED_DIR}/utils/shared_utils.cmake)
include (${SHARED_DIR}/mem-alloc/mem_alloc.cmake)
include (${CJSON_DIR}/cjson.cmake)
include (${SHARED_DIR}/coap/lib_coap.cmake)
include (${SSG_LIB_DIR}/host_agent_lib.cmake)
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32")
endif ()
add_definitions(-Wall -Wno-pointer-sign -DMALLOC_MEMORY_FROM_SYSTEM)
include_directories(
${CMAKE_CURRENT_LIST_DIR}/src
)
file (GLOB_RECURSE HOST_TOOL_SRC src/*.c)
SET(SOURCES
${HOST_TOOL_SRC}
${PLATFORM_SHARED_SOURCE}
${UTILS_SHARED_SOURCE}
${MEM_ALLOC_DIR}/bh_memory.c
${NATIVE_INTERFACE_SOURCE}
${CJSON_SOURCE}
${LIB_HOST_AGENT_SOURCE}
)
add_executable(host_tool ${SOURCES})
target_link_libraries(host_tool pthread)

View File

@ -0,0 +1,20 @@
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
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.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,281 @@
/*
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
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
#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
#define __WINDOWS__
#endif
#ifdef __WINDOWS__
/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options:
CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols
CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default)
CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol
For *nix builds that support visibility attribute, you can define similar behavior by
setting default visibility to hidden by adding
-fvisibility=hidden (for gcc)
or
-xldscope=hidden (for sun cc)
to CFLAGS
then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does
*/
#define CJSON_CDECL __cdecl
#define CJSON_STDCALL __stdcall
/* export symbols by default, this is necessary for copy pasting the C and header file */
#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS)
#define CJSON_EXPORT_SYMBOLS
#endif
#if defined(CJSON_HIDE_SYMBOLS)
#define CJSON_PUBLIC(type) type CJSON_STDCALL
#elif defined(CJSON_EXPORT_SYMBOLS)
#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL
#elif defined(CJSON_IMPORT_SYMBOLS)
#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL
#endif
#else /* !__WINDOWS__ */
#define CJSON_CDECL
#define CJSON_STDCALL
#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY)
#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type
#else
#define CJSON_PUBLIC(type) type
#endif
#endif
/* project version */
#define CJSON_VERSION_MAJOR 1
#define CJSON_VERSION_MINOR 7
#define CJSON_VERSION_PATCH 10
#include <stddef.h>
/* cJSON Types: */
#define cJSON_Invalid (0)
#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_Raw (1 << 7) /* raw json */
#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 and type == cJSON_Raw */
char *valuestring;
/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
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 {
/* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */
void *(CJSON_CDECL *malloc_fn)(size_t sz);
void (CJSON_CDECL *free_fn)(void *ptr);
} cJSON_Hooks;
typedef int cJSON_bool;
/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them.
* This is to prevent stack overflows. */
#ifndef CJSON_NESTING_LIMIT
#define CJSON_NESTING_LIMIT 1000
#endif
/* returns the version of cJSON as a string */
CJSON_PUBLIC(const char*) cJSON_Version(void);
/* Supply malloc, realloc and free functions to cJSON */
CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);
/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
/* 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 so will match cJSON_GetErrorPtr(). */
CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
/* Render a cJSON entity to text for transfer/storage. */
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
/* Render a cJSON entity to text for transfer/storage without any formatting. */
CJSON_PUBLIC(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 */
CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);
/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */
/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */
CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);
/* Delete a cJSON entity and all subentities. */
CJSON_PUBLIC(void) cJSON_Delete(cJSON *c);
/* Returns the number of items in an array (or object). */
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */
CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
/* Get item "string" from object. Case insensitive. */
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string);
CJSON_PUBLIC(cJSON_bool) 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. */
CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
/* Check if the item is a string and return its valuestring */
CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item);
/* These functions check the type of an item */
CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item);
/* These calls create a cJSON item of the appropriate type. */
CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
/* raw json */
CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
/* Create a string where valuestring references a string so
* it will not be freed by cJSON_Delete */
CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string);
/* Create an object/arrray that only references it's elements so
* they will not be freed by cJSON_Delete */
CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);
/* These utilities create an Array of count items. */
CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count);
/* Append item to the specified array/object. */
CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item);
CJSON_PUBLIC(void) cJSON_AddItemToObject(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.
* WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before
* writing to `item->string` */
CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
/* 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. */
CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
/* Remove/Detatch items from Arrays/Objects. */
CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item);
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);
/* Update array items. */
CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement);
CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem);
/* Duplicate a cJSON item */
CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool 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. */
/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal.
* case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */
CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive);
CJSON_PUBLIC(void) cJSON_Minify(char *json);
/* Helper functions for creating and adding items to an object at the same time.
* They return the added item or NULL on failure. */
CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);
CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name);
/* When assigning an integer value, it needs to be propagated to valuedouble too. */
#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
/* helper for the cJSON_SetNumberValue macro */
CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))
/* Macro for iterating over an array or object */
#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)
/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */
CJSON_PUBLIC(void *) cJSON_malloc(size_t size);
CJSON_PUBLIC(void) cJSON_free(void *object);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,10 @@
set (CJSON_DIR ${CMAKE_CURRENT_LIST_DIR})
include_directories(${CJSON_DIR})
file (GLOB_RECURSE source_all ${CJSON_DIR}/*.c)
set (CJSON_SOURCE ${source_all})

View File

@ -0,0 +1,311 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "host_tool_utils.h"
#include "shared_utils.h"
#include <time.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
typedef union jvalue {
bool z;
int8_t b;
uint16_t c;
int16_t s;
int32_t i;
int64_t j;
float f;
double d;
} jvalue;
#define bh_memcpy_s(dest, dlen, src, slen) do { \
int _ret = slen == 0 ? 0 : b_memcpy_s (dest, dlen, src, slen); \
(void)_ret; \
} while (0)
static inline int16_t get_int16(const char *buf)
{
int16_t ret;
bh_memcpy_s(&ret, sizeof(int16_t), buf, sizeof(int16_t));
return ret;
}
static inline uint16_t get_uint16(const char *buf)
{
return get_int16(buf);
}
static inline int32_t get_int32(const char *buf)
{
int32_t ret;
bh_memcpy_s(&ret, sizeof(int32_t), buf, sizeof(int32_t));
return ret;
}
static inline uint32_t get_uint32(const char *buf)
{
return get_int32(buf);
}
char* attr_container_get_attr_begin(const attr_container_t *attr_cont,
uint32_t *p_total_length,
uint16_t *p_attr_num);
cJSON *attr2json(const attr_container_t *attr_cont)
{
uint32_t total_length;
uint16_t attr_num, i, j, type;
const char *p, *tag, *key;
jvalue value;
cJSON *root;
if (!attr_cont)
return NULL;
root = cJSON_CreateObject();
if (!root)
return NULL;
/* TODO: how to convert the tag? */
tag = attr_container_get_tag(attr_cont);
if (!tag)
goto fail;
p = attr_container_get_attr_begin(attr_cont, &total_length, &attr_num);
if (!p)
goto fail;
for (i = 0; i < attr_num; i++) {
cJSON *obj;
key = p + 2;
/* Skip key len and key */
p += 2 + get_uint16(p);
type = *p++;
switch (type) {
case ATTR_TYPE_SHORT:
bh_memcpy_s(&value.s, sizeof(int16_t), p, sizeof(int16_t));
if (NULL == (obj = cJSON_CreateNumber(value.s)))
goto fail;
cJSON_AddItemToObject(root, key, obj);
/* another approach: cJSON_AddNumberToObject(root, key, value.s) */
p += 2;
break;
case ATTR_TYPE_INT:
bh_memcpy_s(&value.i, sizeof(int32_t), p, sizeof(int32_t));
if (NULL == (obj = cJSON_CreateNumber(value.i)))
goto fail;
cJSON_AddItemToObject(root, key, obj);
p += 4;
break;
case ATTR_TYPE_INT64:
bh_memcpy_s(&value.j, sizeof(uint64_t), p, sizeof(uint64_t));
if (NULL == (obj = cJSON_CreateNumber(value.j)))
goto fail;
cJSON_AddItemToObject(root, key, obj);
p += 8;
break;
case ATTR_TYPE_BYTE:
bh_memcpy_s(&value.b, 1, p, 1);
if (NULL == (obj = cJSON_CreateNumber(value.b)))
goto fail;
cJSON_AddItemToObject(root, key, obj);
p++;
break;
case ATTR_TYPE_UINT16:
bh_memcpy_s(&value.c, sizeof(uint16_t), p, sizeof(uint16_t));
if (NULL == (obj = cJSON_CreateNumber(value.c)))
goto fail;
cJSON_AddItemToObject(root, key, obj);
p += 2;
break;
case ATTR_TYPE_FLOAT:
bh_memcpy_s(&value.f, sizeof(float), p, sizeof(float));
if (NULL == (obj = cJSON_CreateNumber(value.f)))
goto fail;
cJSON_AddItemToObject(root, key, obj);
p += 4;
break;
case ATTR_TYPE_DOUBLE:
bh_memcpy_s(&value.d, sizeof(double), p, sizeof(double));
if (NULL == (obj = cJSON_CreateNumber(value.d)))
goto fail;
cJSON_AddItemToObject(root, key, obj);
p += 8;
break;
case ATTR_TYPE_BOOLEAN:
bh_memcpy_s(&value.z, 1, p, 1);
if (NULL == (obj = cJSON_CreateBool(value.z)))
goto fail;
cJSON_AddItemToObject(root, key, obj);
p++;
break;
case ATTR_TYPE_STRING:
if (NULL == (obj = cJSON_CreateString(p + sizeof(uint16_t))))
goto fail;
cJSON_AddItemToObject(root, key, obj);
p += sizeof(uint16_t) + get_uint16(p);
break;
case ATTR_TYPE_BYTEARRAY:
if (NULL == (obj = cJSON_CreateArray()))
goto fail;
cJSON_AddItemToObject(root, key, obj);
for (j = 0; j < get_uint32(p); j++) {
cJSON *item = cJSON_CreateNumber(*(p + sizeof(uint32_t) + j));
if (item == NULL)
goto fail;
cJSON_AddItemToArray(obj, item);
}
p += sizeof(uint32_t) + get_uint32(p);
break;
}
}
return root;
fail: cJSON_Delete(root);
return NULL;
}
attr_container_t *json2attr(const cJSON *json_obj)
{
attr_container_t *attr_cont;
cJSON *item;
if (NULL == (attr_cont = attr_container_create("")))
return NULL;
if (!cJSON_IsObject(json_obj))
goto fail;
cJSON_ArrayForEach(item, json_obj)
{
if (cJSON_IsNumber(item)) {
attr_container_set_double(&attr_cont, item->string,
item->valuedouble);
} else if (cJSON_IsTrue(item)) {
attr_container_set_bool(&attr_cont, item->string, true);
} else if (cJSON_IsFalse(item)) {
attr_container_set_bool(&attr_cont, item->string, false);
} else if (cJSON_IsString(item)) {
attr_container_set_string(&attr_cont, item->string,
item->valuestring);
} else if (cJSON_IsArray(item)) {
int8_t *array;
int i = 0, len = sizeof(int8_t) * cJSON_GetArraySize(item);
cJSON *array_item;
if (0 == len || NULL == (array = (int8_t *) malloc(len)))
goto fail;
memset(array, 0, len);
cJSON_ArrayForEach(array_item, item)
{
/* must be number array */
if (!cJSON_IsNumber(array_item))
break;
/* TODO: if array_item->valuedouble > 127 or < -128 */
array[i++] = (int8_t) array_item->valuedouble;
}
if (i > 0)
attr_container_set_bytearray(&attr_cont, item->string, array,
i);
free(array);
}
}
return attr_cont;
fail: attr_container_destroy(attr_cont);
return NULL;
}
int g_mid = 0;
int gen_random_id()
{
static bool init = false;
int r;
if (!init) {
srand(time(NULL));
init = true;
}
r = rand();
g_mid = r;
return r;
}
char *
read_file_to_buffer(const char *filename, int *ret_size)
{
char *buffer;
int file;
int file_size, read_size;
struct stat stat_buf;
if (!filename || !ret_size) {
return NULL;
}
if ((file = open(filename, O_RDONLY, 0)) == -1) {
return NULL;
}
if (fstat(file, &stat_buf) != 0) {
close(file);
return NULL;
}
file_size = stat_buf.st_size;
if (!(buffer = malloc(file_size))) {
close(file);
return NULL;
}
read_size = read(file, buffer, file_size);
close(file);
if (read_size < file_size) {
free(buffer);
return NULL;
}
*ret_size = file_size;
return buffer;
}
int wirte_buffer_to_file(const char *filename, const char *buffer, int size)
{
int file, ret;
if ((file = open(filename, O_RDWR | O_CREAT | O_APPEND, 0644)) == -1)
return -1;
ret = write(file, buffer, size);
close(file);
return ret;
}

View File

@ -0,0 +1,83 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _HOST_TOOL_UTILS_H_
#define _HOST_TOOL_UTILS_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "attr_container.h"
#include "cJSON.h"
/**
* @brief Convert attribute container object to cJSON object.
*
* @param attr the attribute container object to be converted
*
* @return the created cJSON object if not NULL, NULL means fail
*
* @warning the return object should be deleted with cJSON_Delete by caller
*/
cJSON *attr2json(const attr_container_t *attr);
/**
* @brief Convert cJSON object to attribute container object.
*
* @param json the cJSON object to be converted
*
* @return the created attribute container object if not NULL, NULL means fail
*
* @warning the return object should be deleted with attr_container_destroy
*/
attr_container_t *json2attr(const cJSON *json);
/**
* @brief Generate a random 32 bit integer.
*
* @return the generated random integer
*/
int gen_random_id();
/**
* @brief Read file content to buffer.
*
* @param filename the file name to read
* @param ret_size pointer of integer to save file size once return success
*
* @return the created buffer which contains file content if not NULL, NULL means fail
*
* @warning the return buffer should be deleted with free by caller
*/
char *read_file_to_buffer(const char *filename, int *ret_size);
/**
* @brief Write buffer content to file.
*
* @param filename name the file name to be written
* @param buffer the buffer
* @param size size of the buffer to be written
*
* @return < 0 means fail, > 0 means the number of bytes actually written
*/
int wirte_buffer_to_file(const char *filename, const char *buffer, int size);
#ifdef __cplusplus
} /* end of extern "C" */
#endif
#endif

View File

@ -0,0 +1,930 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <getopt.h>
#include <termios.h>
#include "host_tool_utils.h"
#include "shared_utils.h"
#include "attr_container.h"
#include "coap_ext.h"
#include "cJSON.h"
#include "app_manager_export.h" /* for Module_WASM_App */
#include "host_link.h" /* for REQUEST_PACKET */
#include "transport.h"
#include "iagent_bsp.h" /* for bh_get_elpased_ms */
#define BUF_SIZE 1024
#define TIMEOUT_EXIT_CODE 2
#define URL_MAX_LEN 256
#define DEFAULT_TIMEOUT_MS 5000
#define DEFAULT_ALIVE_TIME_MS 0
#define CONNECTION_MODE_TCP 1
#define CONNECTION_MODE_UART 2
typedef enum {
INSTALL, UNINSTALL, QUERY, REQUEST, REGISTER, UNREGISTER
} op_type;
typedef struct {
const char *file;
const char *name;
const char *module_type;
int heap_size;
/* max timers number */
int timers;
int watchdog_interval;
} inst_info;
typedef struct {
const char *name;
const char *module_type;
} uninst_info;
typedef struct {
const char *name;
} query_info;
typedef struct {
const char *url;
int action;
const char *json_payload_file;
} req_info;
typedef struct {
const char *urls;
} reg_info;
typedef struct {
const char *urls;
} unreg_info;
typedef union operation_info {
inst_info inst;
uninst_info uinst;
query_info query;
req_info req;
reg_info reg;
unreg_info unreg;
} operation_info;
typedef struct {
op_type type;
operation_info info;
} operation;
typedef enum REPLY_PACKET_TYPE {
REPLY_TYPE_EVENT = 0, REPLY_TYPE_RESPONSE = 1
} REPLY_PACKET_TYPE;
/* Package Type */
typedef enum {
Wasm_Module_Bytecode = 0, Wasm_Module_AoT, Package_Type_Unknown = 0xFFFF
} PackageType;
static uint32_t g_timeout_ms = DEFAULT_TIMEOUT_MS;
static uint32_t g_alive_time_ms = DEFAULT_ALIVE_TIME_MS;
static char *g_redirect_file_name = NULL;
static int g_redirect_udp_port = -1;
static int g_conn_fd; /* may be tcp or uart */
static char *g_server_addr = "127.0.0.1";
static int g_server_port = 8888;
static char *g_uart_dev = "/dev/ttyS2";
static int g_baudrate = B115200;
static int g_connection_mode = CONNECTION_MODE_TCP;
extern int g_mid;
extern unsigned char leading[2];
/* -1 fail, 0 success */
static int send_request(request_t *request, bool is_install_wasm_bytecode_app)
{
char *req_p;
int req_size, req_size_n, ret = -1;
uint16_t msg_type = REQUEST_PACKET;
if (is_install_wasm_bytecode_app)
msg_type = INSTALL_WASM_BYTECODE_APP;
if ((req_p = pack_request(request, &req_size)) == NULL)
return -1;
/* leanding bytes */
if (!host_tool_send_data(g_conn_fd, leading, sizeof(leading)))
goto ret;
/* message type */
msg_type = htons(msg_type);
if (!host_tool_send_data(g_conn_fd, (char *) &msg_type, sizeof(msg_type)))
goto ret;
/* payload length */
req_size_n = htonl(req_size);
if (!host_tool_send_data(g_conn_fd, (char *) &req_size_n,
sizeof(req_size_n)))
goto ret;
/* payload */
if (!host_tool_send_data(g_conn_fd, req_p, req_size))
goto ret;
ret = 0;
ret: free_req_resp_packet(req_p);
return ret;
}
static PackageType get_package_type(const char *buf, int size)
{
if (buf && size > 4) {
if (buf[0] == '\0' && buf[1] == 'a' && buf[2] == 's' && buf[3] == 'm')
return Wasm_Module_Bytecode;
if (buf[0] == '\0' && buf[1] == 'a' && buf[2] == 'o' && buf[3] == 't')
return Wasm_Module_AoT;
}
return Package_Type_Unknown;
}
#define url_remain_space (sizeof(url) - strlen(url))
/*return:
0: success
others: fail*/
static int install(inst_info *info)
{
request_t request[1] = { 0 };
char *app_file_buf;
char url[URL_MAX_LEN] = { 0 };
int ret = -1, app_size;
bool is_wasm_bytecode_app;
snprintf(url, sizeof(url) - 1, "/applet?name=%s", info->name);
if (info->module_type != NULL && url_remain_space > 0)
snprintf(url + strlen(url), url_remain_space, "&type=%s",
info->module_type);
if (info->heap_size > 0 && url_remain_space > 0)
snprintf(url + strlen(url), url_remain_space, "&heap=%d",
info->heap_size);
if (info->timers > 0 && url_remain_space > 0)
snprintf(url + strlen(url), url_remain_space, "&timers=%d",
info->timers);
if (info->watchdog_interval > 0 && url_remain_space > 0)
snprintf(url + strlen(url), url_remain_space, "&wd=%d",
info->watchdog_interval);
/*TODO: permissions to access JLF resource: AUDIO LOCATION SENSOR VISION platform.SERVICE */
if ((app_file_buf = read_file_to_buffer(info->file, &app_size)) == NULL)
return -1;
init_request(request, url, COAP_PUT,
FMT_APP_RAW_BINARY, app_file_buf, app_size);
request->mid = gen_random_id();
if ((info->module_type == NULL || strcmp(info->module_type, "wasm") == 0)
&& get_package_type(app_file_buf, app_size) == Wasm_Module_Bytecode)
is_wasm_bytecode_app = true;
else
is_wasm_bytecode_app = false;
ret = send_request(request, is_wasm_bytecode_app);
free(app_file_buf);
return ret;
}
static int uninstall(uninst_info *info)
{
request_t request[1] = { 0 };
char url[URL_MAX_LEN] = { 0 };
snprintf(url, sizeof(url) - 1, "/applet?name=%s", info->name);
if (info->module_type != NULL && url_remain_space > 0)
snprintf(url + strlen(url), url_remain_space, "&type=%s",
info->module_type);
init_request(request, url, COAP_DELETE,
FMT_ATTR_CONTAINER,
NULL, 0);
request->mid = gen_random_id();
return send_request(request, false);
}
static int query(query_info *info)
{
request_t request[1] = { 0 };
int ret = -1;
char url[URL_MAX_LEN] = { 0 };
if (info->name != NULL)
snprintf(url, sizeof(url) - 1, "/applet?name=%s", info->name);
else
snprintf(url, sizeof(url) - 1, "/applet");
init_request(request, url, COAP_GET,
FMT_ATTR_CONTAINER,
NULL, 0);
request->mid = gen_random_id();
ret = send_request(request, false);
return ret;
}
static int request(req_info *info)
{
request_t request[1] = { 0 };
attr_container_t *payload = NULL;
int ret = -1, payload_len = 0;
if (info->json_payload_file != NULL) {
char *payload_file;
cJSON *json;
int payload_file_size;
if ((payload_file = read_file_to_buffer(info->json_payload_file,
&payload_file_size)) == NULL)
return -1;
if (NULL == (json = cJSON_Parse(payload_file))) {
free(payload_file);
goto fail;
}
if (NULL == (payload = json2attr(json))) {
cJSON_Delete(json);
free(payload_file);
goto fail;
}
payload_len = attr_container_get_serialize_length(payload);
cJSON_Delete(json);
free(payload_file);
}
init_request(request, (char *)info->url, info->action,
FMT_ATTR_CONTAINER, payload, payload_len);
request->mid = gen_random_id();
ret = send_request(request, false);
if (info->json_payload_file != NULL && payload != NULL)
attr_container_destroy(payload);
fail: return ret;
}
/*
TODO: currently only support 1 url.
how to handle multiple responses and set process's exit code?
*/
static int subscribe(reg_info *info)
{
request_t request[1] = { 0 };
int ret = -1;
#if 0
char *p;
p = strtok(info->urls, ",");
while(p != NULL) {
char url[URL_MAX_LEN] = {0};
sprintf(url, "%s%s", "/event/", p);
init_request(request,
url,
COAP_PUT,
FMT_ATTR_CONTAINER,
NULL,
0);
request->mid = gen_random_id();
ret = send_request(request, false);
p = strtok (NULL, ",");
}
#else
char url[URL_MAX_LEN] = { 0 };
char *prefix = info->urls[0] == '/' ? "/event" : "/event/";
sprintf(url, "%s%s", prefix, info->urls);
init_request(request, url, COAP_PUT,
FMT_ATTR_CONTAINER,
NULL, 0);
request->mid = gen_random_id();
ret = send_request(request, false);
#endif
return ret;
}
static int unsubscribe(unreg_info *info)
{
request_t request[1] = { 0 };
int ret = -1;
#if 0
char *p;
p = strtok(info->urls, ",");
while(p != NULL) {
char url[URL_MAX_LEN] = {0};
sprintf(url, "%s%s", "/event/", p);
init_request(request,
url,
COAP_DELETE,
FMT_ATTR_CONTAINER,
NULL,
0);
request->mid = gen_random_id();
ret = send_request(request, false);
p = strtok (NULL, ",");
}
#else
char url[URL_MAX_LEN] = { 0 };
sprintf(url, "%s%s", "/event/", info->urls);
init_request(request, url, COAP_DELETE,
FMT_ATTR_CONTAINER,
NULL, 0);
request->mid = gen_random_id();
ret = send_request(request, false);
#endif
return ret;
}
static int init()
{
if (g_connection_mode == CONNECTION_MODE_TCP) {
int fd;
if (!tcp_init(g_server_addr, g_server_port, &fd))
return -1;
g_conn_fd = fd;
return 0;
} else if (g_connection_mode == CONNECTION_MODE_UART) {
int fd;
if (!uart_init(g_uart_dev, g_baudrate, &fd))
return -1;
g_conn_fd = fd;
return 0;
}
return -1;
}
static void deinit()
{
close(g_conn_fd);
}
static int parse_action(const char *str)
{
if (strcasecmp(str, "PUT") == 0)
return COAP_PUT;
if (strcasecmp(str, "GET") == 0)
return COAP_GET;
if (strcasecmp(str, "DELETE") == 0)
return COAP_DELETE;
if (strcasecmp(str, "POST") == 0)
return COAP_POST;
return -1;
}
static void showUsage()
{
printf("\n");
/*printf("Usage: host_tool [-i|--install]|[-u|--uninstall]|[-q|--query]|[-r|--request]|[-s|--register]|[-d|--deregister] ...\n");*/
printf("Usage:\n\thost_tool -i|-u|-q|-r|-s|-d ...\n\n");
printf("\thost_tool -i <App Name> -f <App File>\n"
"\t\t [--type=<App Type>]\n"
"\t\t [--heap=<Heap Size>]\n"
"\t\t [--timers=<Timers Number>]\n"
"\t\t [--watchdog=<Watchdog Interval>]\n"
"\t\t [<Control Options> ...] \n");
printf("\thost_tool -u <App Name> [<Control Options> ...]\n");
printf("\thost_tool -q[<App Name>][<Control Options> ...]\n");
printf(
"\thost_tool -r <Resource URL> -A <Action> [-p <Payload File>] [<Control Options> ...]\n");
printf("\thost_tool -s <Event URLs> [<Control Options> ...]\n");
printf("\thost_tool -d <Event URLs> [<Control Options> ...]\n\n");
printf(
"\t-i, --install Install an application\n");
printf(
"\t-u, --uninstall Uninstall an application\n");
printf(
"\t-q, --query Query all applications\n");
printf("\t-r, --request Send a request\n");
printf("\t-s, --register Register event(s)\n");
printf("\t-d, --deregister De-register event(s)\n");
printf(
"\t-f, --file Specify app binary file path\n");
printf(
"\t-A, --action Specify action of the request\n");
printf(
"\t-p, --payload Specify payload of the request\n");
printf("\n");
printf("\n\tControl Options:\n");
printf(" \t-S <Address>|--address=<Address> Set server address, default to 127.0.0.1\n");
printf(" \t-P <Port>|--port=<Port> Set server port, default to 8888\n");
printf(" \t-D <Device>|--uart=<Device> Set uart device, default to /dev/ttyS2\n");
printf(" \t-B <Baudrate>|--baudrate=<Baudrate> Set uart device baudrate, default to 115200\n");
printf(
"\t-t <timeout>|--timeout=<timeout> Operation timeout in ms, default to 5000\n");
printf(
"\t-a <alive_time>|--alive=<alive_time> Alive time in ms after last operation done, default to 0\n");
printf(
"\t-o <output_file>|--output=<output_file> Redirect the output to output a file\n");
printf(
"\t-U <udp_port>|--udp=<udp_port> Redirect the output to an UDP port in local machine\n");
printf("\nNotes:\n");
printf("\t<App Name>=name of the application\n");
printf("\t<App File>=path of the application binary file in wasm format\n");
printf(
"\t<Resource URL>=resource descriptor, such as /app/<App Name>/res1 or /res1\n");
printf(
"\t<Event URLs>=event url list separated by ',', such as /event1,/event2,/event3\n");
printf(
"\t<Action>=action of the request, can be PUT, GET, DELETE or POST (case insensitive)\n");
printf("\t<Payload File>=path of the payload file in json format\n");
printf("\t<App Type>=Type of app. Can be 'wasm'(default) or 'jeff'\n");
printf("\t<Heap Size>=Heap size of app.\n");
printf("\t<Timers Number>=Max timers number app can use.\n");
printf("\t<Watchdog Interval>=Watchdog interval in ms.\n");
}
#define CHECK_DUPLICATE_OPERATION do{ \
if (operation_parsed) \
{ \
showUsage(); \
return false; \
} \
}while(0)
#define ERROR_RETURN do{ \
showUsage(); \
return false; \
}while(0)
#define CHECK_ARGS_UNMATCH_OPERATION(op_type) do{ \
if (!operation_parsed || op->type != op_type) \
{ \
showUsage(); \
return false; \
} \
}while(0)
static bool parse_args(int argc, char *argv[], operation *op)
{
int c;
bool operation_parsed = false;
bool conn_mode_parsed = false;
while (1) {
int optIndex = 0;
static struct option longOpts[] = {
{ "install", required_argument, NULL, 'i' },
{ "uninstall", required_argument, NULL, 'u' },
{ "query", optional_argument, NULL, 'q' },
{ "request", required_argument, NULL, 'r' },
{ "register", required_argument, NULL, 's' },
{ "deregister", required_argument, NULL, 'd' },
{ "timeout", required_argument, NULL, 't' },
{ "alive", required_argument, NULL, 'a' },
{ "output", required_argument, NULL, 'o' },
{ "udp", required_argument, NULL, 'U' },
{ "action", required_argument, NULL, 'A' },
{ "file", required_argument, NULL, 'f' },
{ "payload", required_argument, NULL, 'p' },
{ "type", required_argument, NULL, 0 },
{ "heap", required_argument, NULL, 1 },
{ "timers", required_argument, NULL, 2 },
{ "watchdog", required_argument, NULL, 3 },
{ "address", required_argument, NULL, 'S' },
{ "port", required_argument, NULL, 'P' },
{ "uart_device",required_argument, NULL, 'D' },
{ "baudrate", required_argument, NULL, 'B' },
{ "help", required_argument, NULL, 'h' },
{ 0, 0, 0, 0 }
};
c = getopt_long(argc, argv, "i:u:q::r:s:d:t:a:o:U:A:f:p:S:P:D:B:h",
longOpts, &optIndex);
if (c == -1)
break;
switch (c) {
case 'i':
CHECK_DUPLICATE_OPERATION;
op->type = INSTALL;
op->info.inst.name = optarg;
operation_parsed = true;
break;
case 'u':
CHECK_DUPLICATE_OPERATION;
op->type = UNINSTALL;
op->info.uinst.name = optarg;
operation_parsed = true;
break;
case 'q':
CHECK_DUPLICATE_OPERATION;
op->type = QUERY;
op->info.query.name = optarg;
break;
case 'r':
CHECK_DUPLICATE_OPERATION;
op->type = REQUEST;
op->info.req.url = optarg;
operation_parsed = true;
break;
case 's':
CHECK_DUPLICATE_OPERATION;
op->type = REGISTER;
op->info.reg.urls = optarg;
operation_parsed = true;
break;
case 'd':
CHECK_DUPLICATE_OPERATION;
op->type = UNREGISTER;
op->info.unreg.urls = optarg;
operation_parsed = true;
break;
case 't':
g_timeout_ms = atoi(optarg);
break;
case 'a':
g_alive_time_ms = atoi(optarg);
break;
case 'o':
g_redirect_file_name = optarg;
break;
case 'U':
g_redirect_udp_port = atoi(optarg);
break;
case 'A':
CHECK_ARGS_UNMATCH_OPERATION(REQUEST);
op->info.req.action = parse_action(optarg);
break;
case 'f':
CHECK_ARGS_UNMATCH_OPERATION(INSTALL);
op->info.inst.file = optarg;
break;
case 'p':
CHECK_ARGS_UNMATCH_OPERATION(REQUEST);
op->info.req.json_payload_file = optarg;
break;
/* module type */
case 0:
/* TODO: use bit mask */
/* CHECK_ARGS_UNMATCH_OPERATION(INSTALL | UNINSTALL); */
if (op->type == INSTALL)
op->info.inst.module_type = optarg;
else if (op->type == UNINSTALL)
op->info.uinst.module_type = optarg;
break;
/* heap */
case 1:
CHECK_ARGS_UNMATCH_OPERATION(INSTALL);
op->info.inst.heap_size = atoi(optarg);
break;
/* timers */
case 2:
CHECK_ARGS_UNMATCH_OPERATION(INSTALL);
op->info.inst.timers = atoi(optarg);
break;
/* watchdog */
case 3:
CHECK_ARGS_UNMATCH_OPERATION(INSTALL);
op->info.inst.watchdog_interval = atoi(optarg);
break;
case 'S':
if (conn_mode_parsed) {
showUsage();
return false;
}
g_connection_mode = CONNECTION_MODE_TCP;
g_server_addr = optarg;
conn_mode_parsed = true;
break;
case 'P':
g_server_port = atoi(optarg);
break;
case 'D':
if (conn_mode_parsed) {
showUsage();
return false;
}
g_connection_mode = CONNECTION_MODE_UART;
g_uart_dev = optarg;
conn_mode_parsed = true;
break;
case 'B':
g_baudrate = parse_baudrate(atoi(optarg));
break;
case 'h':
showUsage();
return false;
default:
showUsage();
return false;
}
}
/* check mandatory options for the operation */
switch (op->type) {
case INSTALL:
if (NULL == op->info.inst.file || NULL == op->info.inst.name)
ERROR_RETURN;
break;
case UNINSTALL:
if (NULL == op->info.uinst.name)
ERROR_RETURN;
break;
case QUERY:
break;
case REQUEST:
if (NULL == op->info.req.url || op->info.req.action <= 0)
ERROR_RETURN;
break;
case REGISTER:
if (NULL == op->info.reg.urls)
ERROR_RETURN;
break;
case UNREGISTER:
if (NULL == op->info.unreg.urls)
ERROR_RETURN;
break;
default:
return false;
}
return true;
}
/*
return value:
< 0: not complete message
REPLY_TYPE_EVENT: event(request)
REPLY_TYPE_RESPONSE: response
*/
static int preocess_reply_data(const char *buf, int len,
imrt_link_recv_context_t *ctx)
{
int result = -1;
const char *pos = buf;
#if DEBUG
int i = 0;
for (; i < len; i++) {
printf(" 0x%02x", buf[i]);
}
printf("\n");
#endif
while (len-- > 0) {
result = on_imrt_link_byte_arrive((unsigned char) *pos++, ctx);
switch (result) {
case 0: {
imrt_link_message_t *message = &ctx->message;
if (message->message_type == RESPONSE_PACKET)
return REPLY_TYPE_RESPONSE;
if (message->message_type == REQUEST_PACKET)
return REPLY_TYPE_EVENT;
break;
}
default:
break;
}
}
return -1;
}
static response_t *
parse_response_from_imrtlink(imrt_link_message_t *message, response_t *response)
{
if (!unpack_response(message->payload, message->payload_size, response))
return NULL;
return response;
}
static request_t *
parse_event_from_imrtlink(imrt_link_message_t *message, request_t *request)
{
if (!unpack_request(message->payload, message->payload_size, request))
return NULL;
return request;
}
static void output(const char *header, attr_container_t *payload, int foramt,
int payload_len)
{
cJSON *json = NULL;
char *json_str = NULL;
/* output the header */
printf("%s", header);
if (g_redirect_file_name != NULL)
wirte_buffer_to_file(g_redirect_file_name, header, strlen(header));
if (g_redirect_udp_port > 0 && g_redirect_udp_port < 65535)
udp_send("127.0.0.1", g_redirect_udp_port, header, strlen(header));
if (foramt != FMT_ATTR_CONTAINER || payload == NULL || payload_len <= 0)
return;
if ((json = attr2json(payload)) == NULL)
return;
if ((json_str = cJSON_Print(json)) == NULL) {
cJSON_Delete(json);
return;
}
/* output the payload as json format */
printf("%s", json_str);
if (g_redirect_file_name != NULL)
wirte_buffer_to_file(g_redirect_file_name, json_str, strlen(json_str));
if (g_redirect_udp_port > 0 && g_redirect_udp_port < 65535)
udp_send("127.0.0.1", g_redirect_udp_port, json_str, strlen(json_str));
free(json_str);
cJSON_Delete(json);
}
static void output_response(response_t *obj)
{
char header[32] = { 0 };
snprintf(header, sizeof(header), "\nresponse status %d\n", obj->status);
output(header, obj->payload, obj->fmt, obj->payload_len);
}
static void output_event(request_t *obj)
{
char header[256] = { 0 };
snprintf(header, sizeof(header), "\nreceived an event %s\n", obj->url);
output(header, obj->payload, obj->fmt, obj->payload_len);
}
int main(int argc, char *argv[])
{
int ret;
imrt_link_recv_context_t recv_ctx = { 0 };
char buffer[BUF_SIZE] = { 0 };
uint32_t last_check, total_elpased_ms = 0;
bool is_responsed = false;
operation op;
memset(&op, 0, sizeof(op));
if (!parse_args(argc, argv, &op))
return -1;
//TODO: reconnect 3 times
if (init() != 0)
return -1;
switch (op.type) {
case INSTALL:
ret = install((inst_info *) &op.info.inst);
break;
case UNINSTALL:
ret = uninstall((uninst_info *) &op.info.uinst);
break;
case QUERY:
ret = query((query_info *) &op.info.query);
break;
case REQUEST:
ret = request((req_info *) &op.info.req);
break;
case REGISTER:
ret = subscribe((reg_info *) &op.info.reg);
break;
case UNREGISTER:
ret = unsubscribe((unreg_info *) &op.info.unreg);
break;
default:
goto ret;
}
if (ret != 0)
goto ret;
bh_get_elpased_ms(&last_check);
while (1) {
int result = 0;
fd_set readfds;
struct timeval tv;
total_elpased_ms += bh_get_elpased_ms(&last_check);
if (!is_responsed) {
if (total_elpased_ms >= g_timeout_ms) {
output("operation timeout\n", NULL, 0, 0);
ret = TIMEOUT_EXIT_CODE;
goto ret;
}
} else {
if (total_elpased_ms >= g_alive_time_ms) {
/*ret = 0;*/
goto ret;
}
}
if (g_conn_fd == -1) {
if (init() != 0) {
sleep(1);
continue;
}
}
FD_ZERO(&readfds);
FD_SET(g_conn_fd, &readfds);
tv.tv_sec = 1;
tv.tv_usec = 0;
result = select(FD_SETSIZE, &readfds, NULL, NULL, &tv);
if (result < 0) {
if (errno != EINTR) {
printf("Error in select, errno: 0x%x\n", errno);
ret = -1;
goto ret;
}
} else if (result == 0) { /* select timeout */
} else if (result > 0) {
int n;
if (FD_ISSET(g_conn_fd, &readfds)) {
int reply_type = -1;
n = read(g_conn_fd, buffer, BUF_SIZE);
if (n <= 0) {
g_conn_fd = -1;
continue;
}
reply_type = preocess_reply_data((char *) buffer, n, &recv_ctx);
if (reply_type == REPLY_TYPE_RESPONSE) {
response_t response[1] = { 0 };
parse_response_from_imrtlink(&recv_ctx.message, response);
if (response->mid != g_mid) {
/* ignore invalid response */
continue;
}
is_responsed = true;
ret = response->status;
output_response(response);
if (op.type == REGISTER || op.type == UNREGISTER) {
/* alive time start */
total_elpased_ms = 0;
bh_get_elpased_ms(&last_check);
}
} else if (reply_type == REPLY_TYPE_EVENT) {
request_t event[1] = { 0 };
parse_event_from_imrtlink(&recv_ctx.message, event);
if (op.type == REGISTER || op.type == UNREGISTER) {
output_event(event);
}
}
}
}
} /* end of while(1) */
ret: if (recv_ctx.message.payload != NULL)
free(recv_ctx.message.payload);
deinit();
return ret;
}

View File

@ -0,0 +1,261 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdbool.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <termios.h>
#include <fcntl.h>
#include "transport.h"
#define SA struct sockaddr
unsigned char leading[2] = { 0x12, 0x34 };
bool tcp_init(const char *address, uint16_t port, int *fd)
{
int sock;
struct sockaddr_in servaddr;
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
return false;
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr(address);
servaddr.sin_port = htons(port);
if (connect(sock, (SA*) &servaddr, sizeof(servaddr)) != 0)
return false;
*fd = sock;
return true;
}
int parse_baudrate(int baud)
{
switch (baud) {
case 9600:
return B9600;
case 19200:
return B19200;
case 38400:
return B38400;
case 57600:
return B57600;
case 115200:
return B115200;
case 230400:
return B230400;
case 460800:
return B460800;
case 500000:
return B500000;
case 576000:
return B576000;
case 921600:
return B921600;
case 1000000:
return B1000000;
case 1152000:
return B1152000;
case 1500000:
return B1500000;
case 2000000:
return B2000000;
case 2500000:
return B2500000;
case 3000000:
return B3000000;
case 3500000:
return B3500000;
case 4000000:
return B4000000;
default:
return -1;
}
}
bool uart_init(const char *device, int baudrate, int *fd)
{
int uart_fd;
struct termios uart_term;
uart_fd = open(device, O_RDWR | O_NOCTTY);
if (uart_fd <= 0)
return false;
memset(&uart_term, 0, sizeof(uart_term));
uart_term.c_cflag = baudrate | CS8 | CLOCAL | CREAD;
uart_term.c_iflag = IGNPAR;
uart_term.c_oflag = 0;
/* set noncanonical mode */
uart_term.c_lflag = 0;
uart_term.c_cc[VTIME] = 30;
uart_term.c_cc[VMIN] = 1;
tcflush(uart_fd, TCIFLUSH);
if (tcsetattr(uart_fd, TCSANOW, &uart_term) != 0) {
close(uart_fd);
return false;
}
*fd = uart_fd;
return true;
}
bool udp_send(const char *address, int port, const char *buf, int len)
{
int sockfd;
struct sockaddr_in servaddr;
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 )
return false;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(port);
servaddr.sin_addr.s_addr = INADDR_ANY;
sendto(sockfd, buf, len, MSG_CONFIRM, (const struct sockaddr *) &servaddr,
sizeof(servaddr));
close(sockfd);
return true;
}
bool host_tool_send_data(int fd, const char *buf, unsigned int len)
{
int cnt = 0;
ssize_t ret;
if (fd == -1 || buf == NULL || len <= 0) {
return false;
}
resend: ret = write(fd, buf, len);
if (ret == -1) {
if (errno == ECONNRESET) {
close(fd);
}
// repeat sending if the outbuffer is full
if (errno == EAGAIN || errno == EWOULDBLOCK) {
if (++cnt > 10) {
close(fd);
return false;
}
sleep(1);
goto resend;
}
}
return (ret == len);
}
#define SET_RECV_PHASE(ctx, new_phase) {ctx->phase = new_phase; ctx->size_in_phase = 0;}
/*
* input: 1 byte from remote
* output: parse result
* return: -1 invalid sync byte
* 1 byte added to buffer, waiting more for complete packet
* 0 completed packet
* 2 in receiving payload
*/
int on_imrt_link_byte_arrive(unsigned char ch, imrt_link_recv_context_t *ctx)
{
if (ctx->phase == Phase_Non_Start) {
if (ctx->message.payload) {
free(ctx->message.payload);
ctx->message.payload = NULL;
ctx->message.payload_size = 0;
}
if (leading[0] == ch) {
ctx->phase = Phase_Leading;
} else {
return -1;
}
} else if (ctx->phase == Phase_Leading) {
if (leading[1] == ch) {
SET_RECV_PHASE(ctx, Phase_Type);
} else {
ctx->phase = Phase_Non_Start;
return -1;
}
} else if (ctx->phase == Phase_Type) {
unsigned char *p = (unsigned char *) &ctx->message.message_type;
p[ctx->size_in_phase++] = ch;
if (ctx->size_in_phase == sizeof(ctx->message.message_type)) {
ctx->message.message_type = ntohs(ctx->message.message_type);
SET_RECV_PHASE(ctx, Phase_Size);
}
} else if (ctx->phase == Phase_Size) {
unsigned char * p = (unsigned char *) &ctx->message.payload_size;
p[ctx->size_in_phase++] = ch;
if (ctx->size_in_phase == sizeof(ctx->message.payload_size)) {
ctx->message.payload_size = ntohl(ctx->message.payload_size);
SET_RECV_PHASE(ctx, Phase_Payload);
if (ctx->message.payload) {
free(ctx->message.payload);
ctx->message.payload = NULL;
}
/* no payload */
if (ctx->message.payload_size == 0) {
SET_RECV_PHASE(ctx, Phase_Non_Start);
return 0;
}
if (ctx->message.payload_size > 1024 * 1024) {
SET_RECV_PHASE(ctx, Phase_Non_Start);
return -1;
}
ctx->message.payload = (char *) malloc(ctx->message.payload_size);
SET_RECV_PHASE(ctx, Phase_Payload);
}
} else if (ctx->phase == Phase_Payload) {
ctx->message.payload[ctx->size_in_phase++] = ch;
if (ctx->size_in_phase == ctx->message.payload_size) {
SET_RECV_PHASE(ctx, Phase_Non_Start);
return 0;
}
return 2;
}
return 1;
}

View File

@ -0,0 +1,122 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef DEPS_APP_MGR_HOST_TOOL_SRC_TRANSPORT_H_
#define DEPS_APP_MGR_HOST_TOOL_SRC_TRANSPORT_H_
#ifdef __cplusplus
extern "C" {
#endif
/* IMRT link message between host and WAMR */
typedef struct {
unsigned short message_type;
unsigned long payload_size;
char *payload;
} imrt_link_message_t;
/* The receive phase of IMRT link message */
typedef enum {
Phase_Non_Start, Phase_Leading, Phase_Type, Phase_Size, Phase_Payload
} recv_phase_t;
/* The receive context of IMRT link message */
typedef struct {
recv_phase_t phase;
int size_in_phase;
imrt_link_message_t message;
} imrt_link_recv_context_t;
/**
* @brief Send data to WAMR.
*
* @param fd the connection fd to WAMR
* @param buf the buffer that contains content to be sent
* @param len size of the buffer to be sent
*
* @return true if success, false if fail
*/
bool host_tool_send_data(int fd, const char *buf, unsigned int len);
/**
* @brief Handle one byte of IMRT link message
*
* @param ch the one byte from WAMR to be handled
* @param ctx the receive context
*
* @return -1 invalid sync byte
* 1 byte added to buffer, waiting more for complete packet
* 0 completed packet
* 2 in receiving payload
*/
int on_imrt_link_byte_arrive(unsigned char ch, imrt_link_recv_context_t *ctx);
/**
* @brief Initialize TCP connection with remote server.
*
* @param address the network address of peer
* @param port the network port of peer
* @param fd pointer of integer to save the socket fd once return success
*
* @return true if success, false if fail
*/
bool tcp_init(const char *address, uint16_t port, int *fd);
/**
* @brief Initialize UART connection with remote.
*
* @param device name of the UART device
* @param baudrate baudrate of the device
* @param fd pointer of integer to save the uart fd once return success
*
* @return true if success, false if fail
*/
bool uart_init(const char *device, int baudrate, int *fd);
/**
* @brief Parse UART baudrate from an integer
*
* @param the baudrate interger to be parsed
*
* @return true if success, false if fail
*
* @par
* @code
* int baudrate = parse_baudrate(9600);
* ...
* uart_term.c_cflag = baudrate;
* ...
* @endcode
*/
int parse_baudrate(int baud);
/**
* @brief Send data over UDP.
*
* @param address network address of the remote
* @param port network port of the remote
* @param buf the buffer that contains content to be sent
* @param len size of the buffer to be sent
*
* @return true if success, false if fail
*/
bool udp_send(const char *address, int port, const char *buf, int len);
#ifdef __cplusplus
} /* end of extern "C" */
#endif
#endif /* DEPS_APP_MGR_HOST_TOOL_SRC_TRANSPORT_H_ */