Merge pull request #1084 from bytecodealliance/main

Merge main into dev/fast_jit
This commit is contained in:
Wenyong Huang 2022-04-12 20:09:28 +08:00 committed by GitHub
commit bb5389867f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 1365 additions and 312 deletions

4
.gitignore vendored
View File

@ -23,4 +23,6 @@ product-mini/platforms/linux-sgx/enclave-sample/iwasm
build_out
tests/wamr-test-suites/workspace
!/test-tools/wamr-ide/VSCode-Extension/.vscode
!/test-tools/wamr-ide/VSCode-Extension/.vscode
samples/socket-api/wasm-src/inc/pthread.h

View File

@ -5800,6 +5800,22 @@ index c878a2ac4..ad5945b0a 100644
// Don't allow the caching that lldb_private::Process::ReadMemory does since
// we have it all cached in the trace files.
return DoReadMemory(addr, buf, size, error);
diff --git a/lldb/source/Target/ThreadPlanStepRange.cpp b/lldb/source/Target/ThreadPlanStepRange.cpp
index 896e647bb..f76307016 100644
--- a/lldb/source/Target/ThreadPlanStepRange.cpp
+++ b/lldb/source/Target/ThreadPlanStepRange.cpp
@@ -334,7 +334,10 @@ bool ThreadPlanStepRange::SetNextBranchBreakpoint() {
// If we didn't find a branch, run to the end of the range.
if (branch_index == UINT32_MAX) {
uint32_t last_index = instructions->GetSize() - 1;
- if (last_index - pc_index > 1) {
+ /* This line causes the "step over was treated as step in" issue, we
+ * modify it as a workaround */
+ /* The origin line is: if (last_index - pc_index > 1) { */
+ if (last_index - pc_index >= 1) {
InstructionSP last_inst =
instructions->GetInstructionAtIndex(last_index);
size_t last_inst_size = last_inst->GetOpcode().GetByteSize();
diff --git a/lldb/source/Target/UnixSignals.cpp b/lldb/source/Target/UnixSignals.cpp
index 4ec2e25c7..24c88fe9a 100644
--- a/lldb/source/Target/UnixSignals.cpp

View File

@ -169,6 +169,15 @@
#define WASM_ENABLE_DEBUG_INTERP 0
#endif
#if WASM_ENABLE_DEBUG_INTERP != 0
#ifndef DEBUG_EXECUTION_MEMORY_SIZE
/* 0x85000 is the size required by lldb, if this is changed to a smaller value,
* then the debugger will not be able to evaluate user expressions, other
* functionality such as breakpoint and stepping are not influenced by this */
#define DEBUG_EXECUTION_MEMORY_SIZE 0x85000
#endif
#endif /* end of WASM_ENABLE_DEBUG_INTERP != 0 */
#ifndef WASM_ENABLE_DEBUG_AOT
#define WASM_ENABLE_DEBUG_AOT 0
#endif

View File

@ -1773,6 +1773,33 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
HANDLE_OP_END();
}
/* constant instructions */
HANDLE_OP(WASM_OP_F64_CONST)
HANDLE_OP(WASM_OP_I64_CONST)
{
uint8 *orig_ip = frame_ip;
frame_ip += sizeof(uint64);
addr_ret = GET_OFFSET();
bh_memcpy_s(frame_lp + addr_ret, sizeof(uint64), orig_ip,
sizeof(uint64));
HANDLE_OP_END();
}
HANDLE_OP(WASM_OP_F32_CONST)
HANDLE_OP(WASM_OP_I32_CONST)
{
uint8 *orig_ip = frame_ip;
frame_ip += sizeof(uint32);
addr_ret = GET_OFFSET();
bh_memcpy_s(frame_lp + addr_ret, sizeof(uint32), orig_ip,
sizeof(uint32));
HANDLE_OP_END();
}
/* comparison instructions of i32 */
HANDLE_OP(WASM_OP_I32_EQZ)
{
@ -3496,10 +3523,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
HANDLE_OP(WASM_OP_F64_LOAD)
HANDLE_OP(EXT_OP_GET_LOCAL_FAST)
HANDLE_OP(WASM_OP_GET_LOCAL)
HANDLE_OP(WASM_OP_F64_CONST)
HANDLE_OP(WASM_OP_I64_CONST)
HANDLE_OP(WASM_OP_F32_CONST)
HANDLE_OP(WASM_OP_I32_CONST)
HANDLE_OP(WASM_OP_DROP)
HANDLE_OP(WASM_OP_DROP_64)
HANDLE_OP(WASM_OP_BLOCK)

View File

@ -1828,7 +1828,7 @@ load_function_section(const uint8 *buf, const uint8 *buf_end,
uint32 func_count;
uint64 total_size;
uint32 code_count = 0, code_size, type_index, i, j, k, local_type_index;
uint32 local_count, local_set_count, sub_local_count;
uint32 local_count, local_set_count, sub_local_count, local_cell_num;
uint8 type;
WASMFunction *func;
@ -1954,9 +1954,17 @@ load_function_section(const uint8 *buf, const uint8 *buf_end,
func->param_cell_num = func->func_type->param_cell_num;
func->ret_cell_num = func->func_type->ret_cell_num;
func->local_cell_num =
local_cell_num =
wasm_get_cell_num(func->local_types, func->local_count);
if (local_cell_num > UINT16_MAX) {
set_error_buf(error_buf, error_buf_size,
"local count too large");
return false;
}
func->local_cell_num = (uint16)local_cell_num;
if (!init_function_local_offsets(func, error_buf, error_buf_size))
return false;
@ -4408,8 +4416,8 @@ typedef struct WASMLoaderContext {
/* const buffer */
uint8 *const_buf;
uint16 num_const;
uint16 const_buf_size;
uint16 const_cell_num;
uint32 const_buf_size;
/* processed code */
uint8 *p_code_compiled;
@ -4619,38 +4627,45 @@ wasm_loader_ctx_destroy(WASMLoaderContext *ctx)
}
static WASMLoaderContext *
wasm_loader_ctx_init(WASMFunction *func)
wasm_loader_ctx_init(WASMFunction *func, char *error_buf, uint32 error_buf_size)
{
WASMLoaderContext *loader_ctx =
loader_malloc(sizeof(WASMLoaderContext), NULL, 0);
loader_malloc(sizeof(WASMLoaderContext), error_buf, error_buf_size);
if (!loader_ctx)
return NULL;
loader_ctx->frame_ref_size = 32;
if (!(loader_ctx->frame_ref_bottom = loader_ctx->frame_ref =
loader_malloc(loader_ctx->frame_ref_size, NULL, 0)))
if (!(loader_ctx->frame_ref_bottom = loader_ctx->frame_ref = loader_malloc(
loader_ctx->frame_ref_size, error_buf, error_buf_size)))
goto fail;
loader_ctx->frame_ref_boundary = loader_ctx->frame_ref_bottom + 32;
loader_ctx->frame_csp_size = sizeof(BranchBlock) * 8;
if (!(loader_ctx->frame_csp_bottom = loader_ctx->frame_csp =
loader_malloc(loader_ctx->frame_csp_size, NULL, 0)))
if (!(loader_ctx->frame_csp_bottom = loader_ctx->frame_csp = loader_malloc(
loader_ctx->frame_csp_size, error_buf, error_buf_size)))
goto fail;
loader_ctx->frame_csp_boundary = loader_ctx->frame_csp_bottom + 8;
#if WASM_ENABLE_FAST_INTERP != 0
loader_ctx->frame_offset_size = sizeof(int16) * 32;
if (!(loader_ctx->frame_offset_bottom = loader_ctx->frame_offset =
loader_malloc(loader_ctx->frame_offset_size, NULL, 0)))
loader_malloc(loader_ctx->frame_offset_size, error_buf,
error_buf_size)))
goto fail;
loader_ctx->frame_offset_boundary = loader_ctx->frame_offset_bottom + 32;
loader_ctx->num_const = 0;
loader_ctx->const_buf_size = sizeof(Const) * 8;
if (!(loader_ctx->const_buf =
loader_malloc(loader_ctx->const_buf_size, NULL, 0)))
if (!(loader_ctx->const_buf = loader_malloc(loader_ctx->const_buf_size,
error_buf, error_buf_size)))
goto fail;
if (func->param_cell_num >= (int32)INT16_MAX - func->local_cell_num) {
set_error_buf(error_buf, error_buf_size,
"fast interpreter offset overflow");
goto fail;
}
loader_ctx->start_dynamic_offset = loader_ctx->dynamic_offset =
loader_ctx->max_dynamic_offset =
func->param_cell_num + func->local_cell_num;
@ -4930,6 +4945,24 @@ fail:
LOG_OP("%d\t", value); \
} while (0)
#define emit_uint64(ctx, value) \
do { \
wasm_loader_emit_const(ctx, &value, false); \
LOG_OP("%lld\t", value); \
} while (0)
#define emit_float32(ctx, value) \
do { \
wasm_loader_emit_const(ctx, &value, true); \
LOG_OP("%f\t", value); \
} while (0)
#define emit_float64(ctx, value) \
do { \
wasm_loader_emit_const(ctx, &value, false); \
LOG_OP("%f\t", value); \
} while (0)
static bool
wasm_loader_ctx_reinit(WASMLoaderContext *ctx)
{
@ -4961,6 +4994,28 @@ wasm_loader_ctx_reinit(WASMLoaderContext *ctx)
return true;
}
static void
wasm_loader_emit_const(WASMLoaderContext *ctx, void *value, bool is_32_bit)
{
uint32 size = is_32_bit ? sizeof(uint32) : sizeof(uint64);
if (ctx->p_code_compiled) {
#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
bh_assert(((uintptr_t)ctx->p_code_compiled & 1) == 0);
#endif
bh_memcpy_s(ctx->p_code_compiled,
ctx->p_code_compiled_end - ctx->p_code_compiled, value,
size);
ctx->p_code_compiled += size;
}
else {
#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
bh_assert((ctx->code_compiled_size & 1) == 0);
#endif
ctx->code_compiled_size += size;
}
}
static void
wasm_loader_emit_uint32(WASMLoaderContext *ctx, uint32 value)
{
@ -5290,8 +5345,12 @@ wasm_loader_push_frame_offset(WASMLoaderContext *ctx, uint8 type,
emit_operand(ctx, ctx->dynamic_offset);
*(ctx->frame_offset)++ = ctx->dynamic_offset;
ctx->dynamic_offset++;
if (ctx->dynamic_offset > ctx->max_dynamic_offset)
if (ctx->dynamic_offset > ctx->max_dynamic_offset) {
ctx->max_dynamic_offset = ctx->dynamic_offset;
if (ctx->max_dynamic_offset >= INT16_MAX) {
goto fail;
}
}
}
if (is_32bit_type(type))
@ -5305,10 +5364,19 @@ wasm_loader_push_frame_offset(WASMLoaderContext *ctx, uint8 type,
ctx->frame_offset++;
if (!disable_emit) {
ctx->dynamic_offset++;
if (ctx->dynamic_offset > ctx->max_dynamic_offset)
if (ctx->dynamic_offset > ctx->max_dynamic_offset) {
ctx->max_dynamic_offset = ctx->dynamic_offset;
if (ctx->max_dynamic_offset >= INT16_MAX) {
goto fail;
}
}
}
return true;
fail:
set_error_buf(error_buf, error_buf_size,
"fast interpreter offset overflow");
return false;
}
/* This function should be in front of wasm_loader_pop_frame_ref
@ -5429,8 +5497,11 @@ wasm_loader_get_const_offset(WASMLoaderContext *ctx, uint8 type, void *value,
int16 *offset, char *error_buf,
uint32 error_buf_size)
{
int8 bytes_to_increase;
int16 operand_offset = 0;
Const *c;
/* Search existing constant */
for (c = (Const *)ctx->const_buf;
(uint8 *)c < ctx->const_buf + ctx->num_const * sizeof(Const); c++) {
/* TODO: handle v128 type? */
@ -5456,7 +5527,24 @@ wasm_loader_get_const_offset(WASMLoaderContext *ctx, uint8 type, void *value,
else
operand_offset += 2;
}
if ((uint8 *)c == ctx->const_buf + ctx->num_const * sizeof(Const)) {
/* New constant, append to the const buffer */
if ((type == VALUE_TYPE_F64) || (type == VALUE_TYPE_I64)) {
bytes_to_increase = 2;
}
else {
bytes_to_increase = 1;
}
/* The max cell num of const buffer is 32768 since the valid index range
* is -32768 ~ -1. Return an invalid index 0 to indicate the buffer is
* full */
if (ctx->const_cell_num > INT16_MAX - bytes_to_increase + 1) {
*offset = 0;
return true;
}
if ((uint8 *)c == ctx->const_buf + ctx->const_buf_size) {
MEM_REALLOC(ctx->const_buf, ctx->const_buf_size,
ctx->const_buf_size + 4 * sizeof(Const));
@ -6386,8 +6474,7 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
local_types = func->local_types;
local_offsets = func->local_offsets;
if (!(loader_ctx = wasm_loader_ctx_init(func))) {
set_error_buf(error_buf, error_buf_size, "allocate memory failed");
if (!(loader_ctx = wasm_loader_ctx_init(func, error_buf, error_buf_size))) {
goto fail;
}
@ -7726,6 +7813,12 @@ re_scan:
skip_label();
disable_emit = true;
GET_CONST_OFFSET(VALUE_TYPE_I32, i32_const);
if (operand_offset == 0) {
disable_emit = false;
emit_label(WASM_OP_I32_CONST);
emit_uint32(loader_ctx, i32_const);
}
#else
(void)i32_const;
#endif
@ -7738,6 +7831,12 @@ re_scan:
skip_label();
disable_emit = true;
GET_CONST_OFFSET(VALUE_TYPE_I64, i64_const);
if (operand_offset == 0) {
disable_emit = false;
emit_label(WASM_OP_I64_CONST);
emit_uint64(loader_ctx, i64_const);
}
#endif
PUSH_I64();
break;
@ -7750,6 +7849,12 @@ re_scan:
bh_memcpy_s((uint8 *)&f32_const, sizeof(float32), p_org,
sizeof(float32));
GET_CONST_F32_OFFSET(VALUE_TYPE_F32, f32_const);
if (operand_offset == 0) {
disable_emit = false;
emit_label(WASM_OP_F32_CONST);
emit_float32(loader_ctx, f32_const);
}
#endif
PUSH_F32();
break;
@ -7763,6 +7868,12 @@ re_scan:
bh_memcpy_s((uint8 *)&f64_const, sizeof(float64), p_org,
sizeof(float64));
GET_CONST_F64_OFFSET(VALUE_TYPE_F64, f64_const);
if (operand_offset == 0) {
disable_emit = false;
emit_label(WASM_OP_F64_CONST);
emit_float64(loader_ctx, f64_const);
}
#endif
PUSH_F64();
break;

View File

@ -914,7 +914,7 @@ load_function_section(const uint8 *buf, const uint8 *buf_end,
uint32 func_count;
uint64 total_size;
uint32 code_count = 0, code_size, type_index, i, j, k, local_type_index;
uint32 local_count, local_set_count, sub_local_count;
uint32 local_count, local_set_count, sub_local_count, local_cell_num;
uint8 type;
WASMFunction *func;
@ -1005,8 +1005,11 @@ load_function_section(const uint8 *buf, const uint8 *buf_end,
func->param_cell_num = func->func_type->param_cell_num;
func->ret_cell_num = func->func_type->ret_cell_num;
func->local_cell_num =
local_cell_num =
wasm_get_cell_num(func->local_types, func->local_count);
bh_assert(local_cell_num <= UINT16_MAX);
func->local_cell_num = (uint16)local_cell_num;
if (!init_function_local_offsets(func, error_buf, error_buf_size))
return false;
@ -2993,8 +2996,8 @@ typedef struct WASMLoaderContext {
/* const buffer */
uint8 *const_buf;
uint16 num_const;
uint16 const_buf_size;
uint16 const_cell_num;
uint32 const_buf_size;
/* processed code */
uint8 *p_code_compiled;
@ -3179,38 +3182,45 @@ wasm_loader_ctx_destroy(WASMLoaderContext *ctx)
}
static WASMLoaderContext *
wasm_loader_ctx_init(WASMFunction *func)
wasm_loader_ctx_init(WASMFunction *func, char *error_buf, uint32 error_buf_size)
{
WASMLoaderContext *loader_ctx =
loader_malloc(sizeof(WASMLoaderContext), NULL, 0);
loader_malloc(sizeof(WASMLoaderContext), error_buf, error_buf_size);
if (!loader_ctx)
return false;
return NULL;
loader_ctx->frame_ref_size = 32;
if (!(loader_ctx->frame_ref_bottom = loader_ctx->frame_ref =
loader_malloc(loader_ctx->frame_ref_size, NULL, 0)))
if (!(loader_ctx->frame_ref_bottom = loader_ctx->frame_ref = loader_malloc(
loader_ctx->frame_ref_size, error_buf, error_buf_size)))
goto fail;
loader_ctx->frame_ref_boundary = loader_ctx->frame_ref_bottom + 32;
loader_ctx->frame_csp_size = sizeof(BranchBlock) * 8;
if (!(loader_ctx->frame_csp_bottom = loader_ctx->frame_csp =
loader_malloc(loader_ctx->frame_csp_size, NULL, 0)))
if (!(loader_ctx->frame_csp_bottom = loader_ctx->frame_csp = loader_malloc(
loader_ctx->frame_csp_size, error_buf, error_buf_size)))
goto fail;
loader_ctx->frame_csp_boundary = loader_ctx->frame_csp_bottom + 8;
#if WASM_ENABLE_FAST_INTERP != 0
loader_ctx->frame_offset_size = sizeof(int16) * 32;
if (!(loader_ctx->frame_offset_bottom = loader_ctx->frame_offset =
loader_malloc(loader_ctx->frame_offset_size, NULL, 0)))
loader_malloc(loader_ctx->frame_offset_size, error_buf,
error_buf_size)))
goto fail;
loader_ctx->frame_offset_boundary = loader_ctx->frame_offset_bottom + 32;
loader_ctx->num_const = 0;
loader_ctx->const_buf_size = sizeof(Const) * 8;
if (!(loader_ctx->const_buf =
loader_malloc(loader_ctx->const_buf_size, NULL, 0)))
if (!(loader_ctx->const_buf = loader_malloc(loader_ctx->const_buf_size,
error_buf, error_buf_size)))
goto fail;
if (func->param_cell_num >= (int32)INT16_MAX - func->local_cell_num) {
set_error_buf(error_buf, error_buf_size,
"fast interpreter offset overflow");
goto fail;
}
loader_ctx->start_dynamic_offset = loader_ctx->dynamic_offset =
loader_ctx->max_dynamic_offset =
func->param_cell_num + func->local_cell_num;
@ -3463,6 +3473,24 @@ wasm_loader_pop_frame_csp(WASMLoaderContext *ctx, char *error_buf,
LOG_OP("%d\t", value); \
} while (0)
#define emit_uint64(ctx, value) \
do { \
wasm_loader_emit_const(ctx, &value, false); \
LOG_OP("%lld\t", value); \
} while (0)
#define emit_float32(ctx, value) \
do { \
wasm_loader_emit_const(ctx, &value, true); \
LOG_OP("%f\t", value); \
} while (0)
#define emit_float64(ctx, value) \
do { \
wasm_loader_emit_const(ctx, &value, false); \
LOG_OP("%f\t", value); \
} while (0)
static bool
wasm_loader_ctx_reinit(WASMLoaderContext *ctx)
{
@ -3494,6 +3522,28 @@ wasm_loader_ctx_reinit(WASMLoaderContext *ctx)
return true;
}
static void
wasm_loader_emit_const(WASMLoaderContext *ctx, void *value, bool is_32_bit)
{
uint32 size = is_32_bit ? sizeof(uint32) : sizeof(uint64);
if (ctx->p_code_compiled) {
#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
bh_assert(((uintptr_t)ctx->p_code_compiled & 1) == 0);
#endif
bh_memcpy_s(ctx->p_code_compiled,
ctx->p_code_compiled_end - ctx->p_code_compiled, value,
size);
ctx->p_code_compiled += size;
}
else {
#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
bh_assert((ctx->code_compiled_size & 1) == 0);
#endif
ctx->code_compiled_size += size;
}
}
static void
wasm_loader_emit_uint32(WASMLoaderContext *ctx, uint32 value)
{
@ -3825,8 +3875,10 @@ wasm_loader_push_frame_offset(WASMLoaderContext *ctx, uint8 type,
emit_operand(ctx, ctx->dynamic_offset);
*(ctx->frame_offset)++ = ctx->dynamic_offset;
ctx->dynamic_offset++;
if (ctx->dynamic_offset > ctx->max_dynamic_offset)
if (ctx->dynamic_offset > ctx->max_dynamic_offset) {
ctx->max_dynamic_offset = ctx->dynamic_offset;
bh_assert(ctx->max_dynamic_offset < INT16_MAX);
}
}
if (is_32bit_type(type))
@ -3840,8 +3892,10 @@ wasm_loader_push_frame_offset(WASMLoaderContext *ctx, uint8 type,
ctx->frame_offset++;
if (!disable_emit) {
ctx->dynamic_offset++;
if (ctx->dynamic_offset > ctx->max_dynamic_offset)
if (ctx->dynamic_offset > ctx->max_dynamic_offset) {
ctx->max_dynamic_offset = ctx->dynamic_offset;
bh_assert(ctx->max_dynamic_offset < INT16_MAX);
}
}
return true;
}
@ -3962,8 +4016,11 @@ wasm_loader_get_const_offset(WASMLoaderContext *ctx, uint8 type, void *value,
int16 *offset, char *error_buf,
uint32 error_buf_size)
{
int8 bytes_to_increase;
int16 operand_offset = 0;
Const *c;
/* Search existing constant */
for (c = (Const *)ctx->const_buf;
(uint8 *)c < ctx->const_buf + ctx->num_const * sizeof(Const); c++) {
if ((type == c->value_type)
@ -3988,7 +4045,24 @@ wasm_loader_get_const_offset(WASMLoaderContext *ctx, uint8 type, void *value,
else
operand_offset += 1;
}
if ((uint8 *)c == ctx->const_buf + ctx->num_const * sizeof(Const)) {
/* New constant, append to the const buffer */
if ((type == VALUE_TYPE_F64) || (type == VALUE_TYPE_I64)) {
bytes_to_increase = 2;
}
else {
bytes_to_increase = 1;
}
/* The max cell num of const buffer is 32768 since the valid index range
* is -32768 ~ -1. Return an invalid index 0 to indicate the buffer is
* full */
if (ctx->const_cell_num > INT16_MAX - bytes_to_increase + 1) {
*offset = 0;
return true;
}
if ((uint8 *)c == ctx->const_buf + ctx->const_buf_size) {
MEM_REALLOC(ctx->const_buf, ctx->const_buf_size,
ctx->const_buf_size + 4 * sizeof(Const));
@ -4788,8 +4862,7 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
local_types = func->local_types;
local_offsets = func->local_offsets;
if (!(loader_ctx = wasm_loader_ctx_init(func))) {
set_error_buf(error_buf, error_buf_size, "allocate memory failed");
if (!(loader_ctx = wasm_loader_ctx_init(func, error_buf, error_buf_size))) {
goto fail;
}
@ -5977,6 +6050,12 @@ re_scan:
skip_label();
disable_emit = true;
GET_CONST_OFFSET(VALUE_TYPE_I32, i32_const);
if (operand_offset == 0) {
disable_emit = false;
emit_label(WASM_OP_I32_CONST);
emit_uint32(loader_ctx, i32_const);
}
#else
(void)i32_const;
#endif
@ -5989,6 +6068,12 @@ re_scan:
skip_label();
disable_emit = true;
GET_CONST_OFFSET(VALUE_TYPE_I64, i64_const);
if (operand_offset == 0) {
disable_emit = false;
emit_label(WASM_OP_I64_CONST);
emit_uint64(loader_ctx, i64_const);
}
#endif
PUSH_I64();
break;
@ -6001,6 +6086,12 @@ re_scan:
bh_memcpy_s((uint8 *)&f32_const, sizeof(float32), p_org,
sizeof(float32));
GET_CONST_F32_OFFSET(VALUE_TYPE_F32, f32_const);
if (operand_offset == 0) {
disable_emit = false;
emit_label(WASM_OP_F32_CONST);
emit_float32(loader_ctx, f32_const);
}
#endif
PUSH_F32();
break;
@ -6014,6 +6105,12 @@ re_scan:
bh_memcpy_s((uint8 *)&f64_const, sizeof(float64), p_org,
sizeof(float64));
GET_CONST_F64_OFFSET(VALUE_TYPE_F64, f64_const);
if (operand_offset == 0) {
disable_emit = false;
emit_label(WASM_OP_F64_CONST);
emit_float64(loader_ctx, f64_const);
}
#endif
PUSH_F64();
break;

View File

@ -345,7 +345,8 @@ WASMDebugInstance *
wasm_debug_instance_create(WASMCluster *cluster)
{
WASMDebugInstance *instance;
WASMExecEnv *exec_env;
WASMExecEnv *exec_env = NULL;
wasm_module_inst_t module_inst = NULL;
if (!g_debug_engine || !g_debug_engine->active) {
return NULL;
@ -373,6 +374,24 @@ wasm_debug_instance_create(WASMCluster *cluster)
instance->current_tid = exec_env->handle;
module_inst = wasm_runtime_get_module_inst(exec_env);
bh_assert(module_inst);
/* Allocate linear memory for evaluating expressions during debugging. If
* the allocation failed, the debugger will not be able to evaluate
* expressions */
instance->exec_mem_info.size = DEBUG_EXECUTION_MEMORY_SIZE;
instance->exec_mem_info.start_offset = wasm_runtime_module_malloc(
module_inst, instance->exec_mem_info.size, NULL);
if (instance->exec_mem_info.start_offset == 0) {
LOG_WARNING(
"WASM Debug Engine warning: failed to allocate linear memory for "
"execution. \n"
"Will not be able to evaluate expressions during "
"debugging");
}
instance->exec_mem_info.current_pos = instance->exec_mem_info.start_offset;
if (!wasm_debug_control_thread_create(instance)) {
LOG_ERROR("WASM Debug Engine error: failed to create control thread");
goto fail3;
@ -1182,9 +1201,7 @@ wasm_debug_instance_mmap(WASMDebugInstance *instance, uint32 size,
int32 map_port)
{
WASMExecEnv *exec_env;
WASMModuleInstance *module_inst;
uint32 offset;
void *native_addr;
uint32 offset = 0;
(void)map_port;
if (!instance)
@ -1194,15 +1211,23 @@ wasm_debug_instance_mmap(WASMDebugInstance *instance, uint32 size,
if (!exec_env)
return 0;
module_inst = (WASMModuleInstance *)exec_env->module_inst;
if (instance->exec_mem_info.start_offset == 0) {
return 0;
}
/* TODO: malloc in wasi libc maybe not be thread safe, we hope LLDB will
always ask for memory when threads stopped */
offset = wasm_runtime_module_malloc((wasm_module_inst_t)module_inst, size,
&native_addr);
if (!offset)
if ((uint64)instance->exec_mem_info.current_pos
- instance->exec_mem_info.start_offset + size
<= (uint64)instance->exec_mem_info.size) {
offset = instance->exec_mem_info.current_pos;
instance->exec_mem_info.current_pos += size;
}
if (offset == 0) {
LOG_WARNING("the memory may be not enough for debug, try use larger "
"--heap-size");
return 0;
}
return WASM_ADDR(WasmMemory, 0, offset);
}
@ -1210,8 +1235,6 @@ bool
wasm_debug_instance_ummap(WASMDebugInstance *instance, uint64 addr)
{
WASMExecEnv *exec_env;
WASMModuleInstance *module_inst;
uint32 offset;
if (!instance)
return false;
@ -1220,11 +1243,13 @@ wasm_debug_instance_ummap(WASMDebugInstance *instance, uint64 addr)
if (!exec_env)
return false;
module_inst = (WASMModuleInstance *)exec_env->module_inst;
if (WASM_ADDR_TYPE(addr) == WasmMemory) {
offset = WASM_ADDR_OFFSET(addr);
wasm_runtime_module_free((wasm_module_inst_t)module_inst, offset);
return true;
if (instance->exec_mem_info.start_offset == 0) {
return false;
}
return false;
(void)addr;
/* Currently we don't support to free the execution memory, simply return
* true here */
return true;
}

View File

@ -44,6 +44,12 @@ typedef enum debug_state_t {
APP_STOPPED
} debug_state_t;
typedef struct WASMDebugExecutionMemory {
uint32 start_offset;
uint32 size;
uint32 current_pos;
} WASMDebugExecutionMemory;
typedef struct WASMDebugInstance {
struct WASMDebugInstance *next;
WASMDebugControlThread *control_thread;
@ -60,6 +66,11 @@ typedef struct WASMDebugInstance {
* RUNNING when receiving STEP/CONTINUE commands, and set to
* STOPPED when any thread stopped */
volatile debug_state_t current_state;
/* Execution memory info. During debugging, the debug client may request to
* malloc a memory space to evaluate user expressions. We preserve a buffer
* during creating debug instance, and use a simple bump pointer allocator
* to serve lldb's memory request */
WASMDebugExecutionMemory exec_mem_info;
} WASMDebugInstance;
typedef enum WASMDebugEventKind {

View File

@ -80,6 +80,12 @@ connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
int
listen(int sockfd, int backlog);
ssize_t
recvmsg(int sockfd, struct msghdr *msg, int flags);
ssize_t
sendmsg(int sockfd, const struct msghdr *msg, int flags);
int
socket(int domain, int type, int protocol);
#endif

View File

@ -7,6 +7,7 @@
#include <errno.h>
#include <netinet/in.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <wasi/api.h>
#include <wasi_socket_ext.h>
@ -126,6 +127,10 @@ connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
__wasi_addr_t wasi_addr = { 0 };
__wasi_errno_t error;
if (NULL == addr) {
HANDLE_ERROR(__WASI_ERRNO_INVAL)
}
error = sockaddr_to_wasi_addr(addr, addrlen, &wasi_addr);
HANDLE_ERROR(error)
@ -143,6 +148,79 @@ listen(int sockfd, int backlog)
return __WASI_ERRNO_SUCCESS;
}
ssize_t
recvmsg(int sockfd, struct msghdr *msg, int flags)
{
// Prepare input parameters.
__wasi_iovec_t *ri_data = NULL;
size_t i = 0;
size_t ro_datalen;
__wasi_roflags_t ro_flags;
if (NULL == msg) {
HANDLE_ERROR(__WASI_ERRNO_INVAL)
}
// Validate flags.
if (flags != 0) {
HANDLE_ERROR(__WASI_ERRNO_NOPROTOOPT)
}
// __wasi_ciovec_t -> struct iovec
if (!(ri_data = malloc(sizeof(__wasi_iovec_t) * msg->msg_iovlen))) {
HANDLE_ERROR(__WASI_ERRNO_NOMEM)
}
for (i = 0; i < msg->msg_iovlen; i++) {
ri_data[i].buf = msg->msg_iov[i].iov_base;
ri_data[i].buf_len = msg->msg_iov[i].iov_len;
}
// Perform system call.
__wasi_errno_t error = __wasi_sock_recv(sockfd, ri_data, msg->msg_iovlen, 0,
&ro_datalen, &ro_flags);
free(ri_data);
HANDLE_ERROR(error)
return ro_datalen;
}
ssize_t
sendmsg(int sockfd, const struct msghdr *msg, int flags)
{
// Prepare input parameters.
__wasi_ciovec_t *si_data = NULL;
size_t so_datalen = 0;
size_t i = 0;
if (NULL == msg) {
HANDLE_ERROR(__WASI_ERRNO_INVAL)
}
// This implementation does not support any flags.
if (flags != 0) {
HANDLE_ERROR(__WASI_ERRNO_NOPROTOOPT)
}
// struct iovec -> __wasi_ciovec_t
if (!(si_data = malloc(sizeof(__wasi_ciovec_t) * msg->msg_iovlen))) {
HANDLE_ERROR(__WASI_ERRNO_NOMEM)
}
for (i = 0; i < msg->msg_iovlen; i++) {
si_data[i].buf = msg->msg_iov[i].iov_base;
si_data[i].buf_len = msg->msg_iov[i].iov_len;
}
// Perform system call.
__wasi_errno_t error =
__wasi_sock_send(sockfd, si_data, msg->msg_iovlen, 0, &so_datalen);
free(si_data);
HANDLE_ERROR(error)
return so_datalen;
}
int
socket(int domain, int type, int protocol)
{

View File

@ -60,119 +60,54 @@ wasm_runtime_module_realloc(wasm_module_inst_t module, uint32 ptr, uint32 size,
typedef int (*out_func_t)(int c, void *ctx);
enum pad_type {
PAD_NONE,
PAD_ZERO_BEFORE,
PAD_SPACE_BEFORE,
PAD_SPACE_AFTER,
};
typedef char *_va_list;
#define _INTSIZEOF(n) (((uint32)sizeof(n) + 3) & (uint32)~3)
#define _va_arg(ap, t) (*(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)))
#define CHECK_VA_ARG(ap, t) \
do { \
if ((uint8 *)ap + _INTSIZEOF(t) > native_end_addr) \
goto fail; \
#define CHECK_VA_ARG(ap, t) \
do { \
if ((uint8 *)ap + _INTSIZEOF(t) > native_end_addr) { \
if (fmt_buf != temp_fmt) { \
wasm_runtime_free(fmt_buf); \
} \
goto fail; \
} \
} while (0)
/**
* @brief Output an unsigned int in hex format
*
* Output an unsigned int on output installed by platform at init time. Should
* be able to handle an unsigned int of any size, 32 or 64 bit.
* @param num Number to output
*
* @return N/A
*/
static void
_printf_hex_uint(out_func_t out, void *ctx, const uint64 num, bool is_u64,
enum pad_type padding, int min_width)
{
int shift = sizeof(num) * 8;
int found_largest_digit = 0;
int remaining = 16; /* 16 digits max */
int digits = 0;
char nibble;
/* clang-format off */
#define PREPARE_TEMP_FORMAT() \
char temp_fmt[32], *s, *fmt_buf = temp_fmt; \
uint32 fmt_buf_len = (uint32)sizeof(temp_fmt); \
int32 n; \
\
/* additional 2 bytes: one is the format char, \
* the other is `\0` */ \
if (fmt - fmt_start_addr + 2 >= fmt_buf_len) { \
bh_assert(fmt - fmt_start_addr <= UINT32_MAX - 2); \
fmt_buf_len = fmt - fmt_start_addr + 2; \
if (!(fmt_buf = wasm_runtime_malloc(fmt_buf_len))) { \
print_err(out, ctx); \
break; \
} \
} \
\
memset(fmt_buf, 0, fmt_buf_len); \
bh_memcpy_s(fmt_buf, fmt_buf_len, \
fmt_start_addr, fmt - fmt_start_addr + 1);
/* clang-format on */
while (shift >= 4) {
shift -= 4;
nibble = (num >> shift) & 0xf;
if (nibble || found_largest_digit || shift == 0) {
found_largest_digit = 1;
nibble = (char)(nibble + (nibble > 9 ? 87 : 48));
out((int)nibble, ctx);
digits++;
continue;
}
if (remaining-- <= min_width) {
if (padding == PAD_ZERO_BEFORE) {
out('0', ctx);
}
else if (padding == PAD_SPACE_BEFORE) {
out(' ', ctx);
}
}
}
if (padding == PAD_SPACE_AFTER) {
remaining = min_width * 2 - digits;
while (remaining-- > 0) {
out(' ', ctx);
}
}
}
/**
* @brief Output an unsigned int in decimal format
*
* Output an unsigned int on output installed by platform at init time. Only
* works with 32-bit values.
* @param num Number to output
*
* @return N/A
*/
static void
_printf_dec_uint(out_func_t out, void *ctx, const uint32 num,
enum pad_type padding, int min_width)
{
uint32 pos = 999999999;
uint32 remainder = num;
int found_largest_digit = 0;
int remaining = 10; /* 10 digits max */
int digits = 1;
/* make sure we don't skip if value is zero */
if (min_width <= 0) {
min_width = 1;
}
while (pos >= 9) {
if (found_largest_digit || remainder > pos) {
found_largest_digit = 1;
out((int)((remainder / (pos + 1)) + 48), ctx);
digits++;
}
else if (remaining <= min_width && padding < PAD_SPACE_AFTER) {
out((int)(padding == PAD_ZERO_BEFORE ? '0' : ' '), ctx);
digits++;
}
remaining--;
remainder %= (pos + 1);
pos /= 10;
}
out((int)(remainder + 48), ctx);
if (padding == PAD_SPACE_AFTER) {
remaining = min_width - digits;
while (remaining-- > 0) {
out(' ', ctx);
}
}
}
#define OUTPUT_TEMP_FORMAT() \
do { \
if (n > 0) { \
s = buf; \
while (*s) \
out((int)(*s++), ctx); \
} \
\
if (fmt_buf != temp_fmt) { \
wasm_runtime_free(fmt_buf); \
} \
} while (0)
static void
print_err(out_func_t out, void *ctx)
@ -187,10 +122,10 @@ _vprintf_wa(out_func_t out, void *ctx, const char *fmt, _va_list ap,
wasm_module_inst_t module_inst)
{
int might_format = 0; /* 1 if encountered a '%' */
enum pad_type padding = PAD_NONE;
int min_width = -1;
int long_ctr = 0;
uint8 *native_end_addr;
const char *fmt_start_addr = NULL;
bool is_signed;
if (!wasm_runtime_get_native_addr_range(module_inst, (uint8 *)ap, NULL,
&native_end_addr))
@ -205,23 +140,19 @@ _vprintf_wa(out_func_t out, void *ctx, const char *fmt, _va_list ap,
}
else {
might_format = 1;
min_width = -1;
padding = PAD_NONE;
long_ctr = 0;
fmt_start_addr = fmt;
is_signed = false;
}
}
else {
switch (*fmt) {
case '.':
case '+':
case '-':
padding = PAD_SPACE_AFTER;
goto still_might_format;
case ' ':
case '#':
case '0':
if (min_width < 0 && padding == PAD_NONE) {
padding = PAD_ZERO_BEFORE;
goto still_might_format;
}
goto handle_1_to_9;
case '1':
case '2':
case '3':
@ -231,17 +162,12 @@ _vprintf_wa(out_func_t out, void *ctx, const char *fmt, _va_list ap,
case '7':
case '8':
case '9':
handle_1_to_9:
if (min_width < 0) {
min_width = *fmt - '0';
}
else {
min_width = 10 * min_width + *fmt - '0';
}
case 't': /* ptrdiff_t */
goto still_might_format;
if (padding == PAD_NONE) {
padding = PAD_SPACE_BEFORE;
}
case 'j':
/* intmax_t/uintmax_t */
long_ctr = 2;
goto still_might_format;
case 'l':
@ -252,113 +178,108 @@ _vprintf_wa(out_func_t out, void *ctx, const char *fmt, _va_list ap,
/* FIXME: do nothing for these modifiers */
goto still_might_format;
case 'o':
case 'd':
case 'i':
{
int32 d;
if (long_ctr < 2) {
CHECK_VA_ARG(ap, int32);
d = _va_arg(ap, int32);
}
else {
int64 lld;
CHECK_VA_ARG(ap, int64);
lld = _va_arg(ap, int64);
if (lld > INT32_MAX || lld < INT32_MIN) {
print_err(out, ctx);
break;
}
d = (int32)lld;
}
if (d < 0) {
out((int)'-', ctx);
d = -d;
min_width--;
}
_printf_dec_uint(out, ctx, (uint32)d, padding, min_width);
break;
}
case 'u':
{
uint32 u;
if (long_ctr < 2) {
CHECK_VA_ARG(ap, uint32);
u = _va_arg(ap, uint32);
}
else {
uint64 llu;
CHECK_VA_ARG(ap, uint64);
llu = _va_arg(ap, uint64);
if (llu > INT32_MAX) {
print_err(out, ctx);
break;
}
u = (uint32)llu;
}
_printf_dec_uint(out, ctx, u, padding, min_width);
break;
}
case 'p':
out('0', ctx);
out('x', ctx);
/* left-pad pointers with zeros */
padding = PAD_ZERO_BEFORE;
min_width = 8;
is_signed = true;
/* Fall through */
case 'u':
case 'p':
case 'x':
case 'X':
case 'c':
{
uint64 x;
bool is_ptr = (*fmt == 'p') ? true : false;
char buf[64];
PREPARE_TEMP_FORMAT();
if (long_ctr < 2) {
CHECK_VA_ARG(ap, uint32);
x = _va_arg(ap, uint32);
if (is_signed) {
int32 d;
d = _va_arg(ap, int32);
n = snprintf(buf, sizeof(buf), fmt_buf, d);
}
else {
uint32 u;
u = _va_arg(ap, uint32);
n = snprintf(buf, sizeof(buf), fmt_buf, u);
}
}
else {
/* Make 8-byte aligned */
ap = (_va_list)(((uintptr_t)ap + 7) & ~(uintptr_t)7);
CHECK_VA_ARG(ap, uint64);
x = _va_arg(ap, uint64);
if (is_signed) {
int64 lld;
lld = _va_arg(ap, int64);
n = snprintf(buf, sizeof(buf), fmt_buf, lld);
}
else {
uint64 llu;
llu = _va_arg(ap, uint64);
n = snprintf(buf, sizeof(buf), fmt_buf, llu);
}
}
_printf_hex_uint(out, ctx, x, !is_ptr, padding, min_width);
OUTPUT_TEMP_FORMAT();
break;
}
case 's':
{
char *s;
char buf_tmp[128], *buf = buf_tmp;
char *start;
uint32 s_offset;
uint32 s_offset, str_len, buf_len;
PREPARE_TEMP_FORMAT();
CHECK_VA_ARG(ap, int32);
s_offset = _va_arg(ap, uint32);
if (!validate_app_str_addr(s_offset)) {
if (fmt_buf != temp_fmt) {
wasm_runtime_free(fmt_buf);
}
return false;
}
s = start = addr_app_to_native(s_offset);
while (*s)
out((int)(*s++), ctx);
str_len = strlen(start);
if (str_len >= UINT32_MAX - 64) {
print_err(out, ctx);
if (fmt_buf != temp_fmt) {
wasm_runtime_free(fmt_buf);
}
break;
}
if (padding == PAD_SPACE_AFTER) {
int remaining = min_width - (int32)(s - start);
while (remaining-- > 0) {
out(' ', ctx);
/* reserve 64 more bytes as there may be width description
* in the fmt */
buf_len = str_len + 64;
if (buf_len > (uint32)sizeof(buf_tmp)) {
if (!(buf = wasm_runtime_malloc(buf_len))) {
print_err(out, ctx);
if (fmt_buf != temp_fmt) {
wasm_runtime_free(fmt_buf);
}
break;
}
}
break;
}
case 'c':
{
int c;
CHECK_VA_ARG(ap, int);
c = _va_arg(ap, int);
out(c, ctx);
n = snprintf(buf, buf_len, fmt_buf,
(s_offset == 0 && str_len == 0) ? NULL
: start);
OUTPUT_TEMP_FORMAT();
if (buf != buf_tmp) {
wasm_runtime_free(buf);
}
break;
}
@ -368,22 +289,31 @@ _vprintf_wa(out_func_t out, void *ctx, const char *fmt, _va_list ap,
break;
}
case 'e':
case 'E':
case 'g':
case 'G':
case 'f':
case 'F':
{
float64 f64;
char buf[16], *s;
char buf[64];
PREPARE_TEMP_FORMAT();
/* Make 8-byte aligned */
ap = (_va_list)(((uintptr_t)ap + 7) & ~(uintptr_t)7);
CHECK_VA_ARG(ap, float64);
f64 = _va_arg(ap, float64);
snprintf(buf, sizeof(buf), "%f", f64);
s = buf;
while (*s)
out((int)(*s++), ctx);
n = snprintf(buf, sizeof(buf), fmt_buf, f64);
OUTPUT_TEMP_FORMAT();
break;
}
case 'n':
/* print nothing */
break;
default:
out((int)'%', ctx);
out((int)*fmt, ctx);

View File

@ -112,7 +112,6 @@ wasi_args_get(wasm_exec_env_t exec_env, uint32 *argv_offsets, char *argv_buf)
for (i = 0; i < argc; i++)
argv_offsets[i] = addr_native_to_app(argv[i]);
argv_offsets[argc] = 0;
wasm_runtime_free(argv);
return 0;
@ -208,7 +207,6 @@ wasi_environ_get(wasm_exec_env_t exec_env, uint32 *environ_offsets,
for (i = 0; i < environ_count; i++)
environ_offsets[i] = addr_native_to_app(environs[i]);
environ_offsets[environ_count] = 0;
wasm_runtime_free(environs);
return 0;

View File

@ -131,7 +131,6 @@ wasi_args_get(wasm_exec_env_t exec_env, uint32 *argv_offsets, char *argv_buf)
for (i = 0; i < argc; i++)
argv_offsets[i] = addr_native_to_app(argv[i]);
argv_offsets[argc] = 0;
wasm_runtime_free(argv);
return 0;
@ -234,7 +233,6 @@ wasi_environ_get(wasm_exec_env_t exec_env, uint32 *environ_offsets,
for (i = 0; i < environ_count; i++)
environ_offsets[i] = addr_native_to_app(environs[i]);
environ_offsets[environ_count] = 0;
wasm_runtime_free(environs);
return 0;

View File

@ -9,21 +9,194 @@
#define TRACE_OCALL_FAIL() os_printf("ocall %s failed!\n", __FUNCTION__)
/** OCALLs prototypes **/
int
ocall_socket(int *p_ret, int domain, int type, int protocol);
ocall_accept(int *p_ret, int sockfd, void *addr, uint32_t *addrlen,
uint32_t addr_size);
int
ocall_bind(int *p_ret, int sockfd, const void *addr, uint32_t addrlen);
int
ocall_close(int *p_ret, int fd);
int
ocall_connect(int *p_ret, int sockfd, void *addr, uint32_t addrlen);
int
ocall_fcntl_long(int *p_ret, int fd, int cmd, long arg);
int
ocall_getsockname(int *p_ret, int sockfd, void *addr, uint32_t *addrlen,
uint32_t addr_size);
int
ocall_getsockopt(int *p_ret, int sockfd, int level, int optname, void *val_buf,
unsigned int val_buf_size, void *len_buf);
int
ocall_sendmsg(ssize_t *p_ret, int sockfd, void *msg_buf,
unsigned int msg_buf_size, int flags);
ocall_listen(int *p_ret, int sockfd, int backlog);
int
ocall_recv(int *p_ret, int sockfd, void *buf, size_t len, int flags);
int
ocall_recvmsg(ssize_t *p_ret, int sockfd, void *msg_buf,
unsigned int msg_buf_size, int flags);
int
ocall_send(int *p_ret, int sockfd, const void *buf, size_t len, int flags);
int
ocall_sendmsg(ssize_t *p_ret, int sockfd, void *msg_buf,
unsigned int msg_buf_size, int flags);
int
ocall_setsockopt(int *p_ret, int sockfd, int level, int optname, void *optval,
unsigned int optlen);
int
ocall_shutdown(int *p_ret, int sockfd, int how);
int
ocall_socket(int *p_ret, int domain, int type, int protocol);
/** OCALLs prototypes end **/
/** In-enclave implementation of POSIX functions **/
static bool
is_little_endian()
{
long i = 0x01020304;
unsigned char *c = (unsigned char *)&i;
return (*c == 0x04) ? true : false;
}
static void
swap32(uint8 *pData)
{
uint8 value = *pData;
*pData = *(pData + 3);
*(pData + 3) = value;
value = *(pData + 1);
*(pData + 1) = *(pData + 2);
*(pData + 2) = value;
}
static void
swap16(uint8 *pData)
{
uint8 value = *pData;
*(pData) = *(pData + 1);
*(pData + 1) = value;
}
static uint32
htonl(uint32 value)
{
uint32 ret;
if (is_little_endian()) {
ret = value;
swap32((uint8 *)&ret);
return ret;
}
return value;
}
static uint32
ntohl(uint32 value)
{
return htonl(value);
}
static uint16
htons(uint16 value)
{
uint16 ret;
if (is_little_endian()) {
ret = value;
swap16((uint8 *)&ret);
return ret;
}
return value;
}
static uint16
ntohs(uint16 value)
{
return htons(value);
}
/* Coming from musl, under MIT license */
static int
__inet_aton(const char *s0, struct in_addr *dest)
{
const char *s = s0;
unsigned char *d = (void *)dest;
unsigned long a[4] = { 0 };
char *z;
int i;
for (i = 0; i < 4; i++) {
a[i] = strtoul(s, &z, 0);
if (z == s || (*z && *z != '.') || !isdigit(*s))
return 0;
if (!*z)
break;
s = z + 1;
}
if (i == 4)
return 0;
switch (i) {
case 0:
a[1] = a[0] & 0xffffff;
a[0] >>= 24;
case 1:
a[2] = a[1] & 0xffff;
a[1] >>= 16;
case 2:
a[3] = a[2] & 0xff;
a[2] >>= 8;
}
for (i = 0; i < 4; i++) {
if (a[i] > 255)
return 0;
d[i] = a[i];
}
return 1;
}
/* Coming from musl, under MIT license */
static int
inet_addr(const char *p)
{
struct in_addr a;
if (!__inet_aton(p, &a))
return -1;
return a.s_addr;
}
static int
inet_network(const char *p)
{
return ntohl(inet_addr(p));
}
/** In-enclave implementation of POSIX functions end **/
static int
textual_addr_to_sockaddr(const char *textual, int port, struct sockaddr_in *out)
{
assert(textual);
out->sin_family = AF_INET;
out->sin_port = htons(port);
out->sin_addr.s_addr = inet_addr(textual);
return BHT_OK;
}
int
socket(int domain, int type, int protocol)
{
@ -232,67 +405,219 @@ os_socket_accept(bh_socket_t server_sock, bh_socket_t *sock, void *addr,
unsigned int *addrlen)
{
errno = ENOSYS;
return -1;
struct sockaddr addr_tmp;
unsigned int len = sizeof(struct sockaddr);
if (ocall_accept(sock, server_sock, &addr_tmp, &len, len) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
if (*sock < 0) {
errno = get_errno();
return BHT_ERROR;
}
return BHT_OK;
}
int
os_socket_bind(bh_socket_t socket, const char *host, int *port)
{
errno = ENOSYS;
return -1;
struct sockaddr_in addr;
struct linger ling;
unsigned int socklen;
int ret;
assert(host);
assert(port);
ling.l_onoff = 1;
ling.l_linger = 0;
if (ocall_fcntl_long(&ret, socket, F_SETFD, FD_CLOEXEC) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
if (ret < 0) {
goto fail;
}
if (ocall_setsockopt(&ret, socket, SOL_SOCKET, SO_LINGER, &ling,
sizeof(ling))
!= SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
if (ret < 0) {
goto fail;
}
addr.sin_addr.s_addr = inet_addr(host);
addr.sin_port = htons(*port);
addr.sin_family = AF_INET;
if (ocall_bind(&ret, socket, &addr, sizeof(addr)) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
if (ret < 0) {
goto fail;
}
socklen = sizeof(addr);
if (ocall_getsockname(&ret, socket, (void *)&addr, &socklen, socklen)
!= SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
if (ret == -1) {
goto fail;
}
*port = ntohs(addr.sin_port);
return BHT_OK;
fail:
errno = get_errno();
return BHT_ERROR;
}
int
os_socket_close(bh_socket_t socket)
{
errno = ENOSYS;
return -1;
int ret;
if (ocall_close(&ret, socket) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
if (ret == -1)
errno = get_errno();
return ret;
}
int
os_socket_connect(bh_socket_t socket, const char *addr, int port)
{}
{
struct sockaddr_in addr_in = { 0 };
socklen_t addr_len = sizeof(struct sockaddr_in);
int ret = 0;
if ((ret = textual_addr_to_sockaddr(addr, port, &addr_in)) < 0) {
return ret;
}
if (ocall_connect(&ret, socket, &addr_in, addr_len) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
if (ret == -1)
errno = get_errno();
return ret;
}
int
os_socket_create(bh_socket_t *sock, int tcp_or_udp)
{
errno = ENOSYS;
return -1;
if (!sock) {
return BHT_ERROR;
}
if (1 == tcp_or_udp) {
if (ocall_socket(sock, AF_INET, SOCK_STREAM, IPPROTO_TCP)
!= SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
}
else if (0 == tcp_or_udp) {
if (ocall_socket(sock, AF_INET, SOCK_DGRAM, 0) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
}
if (*sock == -1) {
errno = get_errno();
return BHT_ERROR;
}
return BHT_OK;
}
int
os_socket_inet_network(const char *cp, uint32 *out)
{
errno = ENOSYS;
return -1;
if (!cp)
return BHT_ERROR;
*out = inet_network(cp);
return BHT_OK;
}
int
os_socket_listen(bh_socket_t socket, int max_client)
{
errno = ENOSYS;
return -1;
int ret;
if (ocall_listen(&ret, socket, max_client) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
if (ret == -1)
errno = get_errno();
return ret;
}
int
os_socket_recv(bh_socket_t socket, void *buf, unsigned int len)
{
errno = ENOSYS;
return -1;
int ret;
if (ocall_recv(&ret, socket, buf, len, 0) != SGX_SUCCESS) {
errno = ENOSYS;
return -1;
}
if (ret == -1)
errno = get_errno();
return ret;
}
int
os_socket_send(bh_socket_t socket, const void *buf, unsigned int len)
{
errno = ENOSYS;
return -1;
int ret;
if (ocall_send(&ret, socket, buf, len, 0) != SGX_SUCCESS) {
errno = ENOSYS;
return -1;
}
if (ret == -1)
errno = get_errno();
return ret;
}
int
os_socket_shutdown(bh_socket_t socket)
{
errno = ENOSYS;
return -1;
return shutdown(socket, O_RDWR);
}
#endif

View File

@ -14,11 +14,12 @@ extern "C" {
#define SOL_SOCKET 1
#define SO_TYPE 3
#define SO_LINGER 13
#define SOCK_STREAM 1
#define SOCK_DGRAM 2
#define SO_TYPE 3
#define MSG_OOB 0x0001
#define MSG_PEEK 0x0002
#define MSG_DONTROUTE 0x0004
@ -44,6 +45,16 @@ extern "C" {
#define SHUT_WR 1
#define SHUT_RDWR 2
/* Address families. */
#define AF_INET 2 /* IP protocol family. */
/* Standard well-defined IP protocols. */
#define IPPROTO_TCP 6 /* Transmission Control Protocol. */
/* Types of sockets. */
#define SOCK_DGRAM \
2 /* Connectionless, unreliable datagrams of fixed maximum length. */
struct msghdr {
void *msg_name;
socklen_t msg_namelen;
@ -54,6 +65,36 @@ struct msghdr {
int msg_flags;
};
/* Internet address. */
struct in_addr {
uint32_t s_addr;
};
typedef struct in_addr in_addr_t;
/* Structure describing an Internet socket address. */
#define __SOCK_SIZE__ 16 /* sizeof(struct sockaddr) */
struct sockaddr_in {
uint16_t sin_family;
uint16_t sin_port; /* Port number. */
struct in_addr sin_addr; /* Internet address. */
/* Pad to size of `struct sockaddr'. */
unsigned char__pad[__SOCK_SIZE__ - sizeof(uint16_t) - sizeof(uint16_t)
- sizeof(struct in_addr)];
};
/* Structure used to manipulate the SO_LINGER option. */
struct linger {
int l_onoff; /* Nonzero to linger on close. */
int l_linger; /* Time to linger. */
};
/* Structure describing a generic socket address. */
struct sockaddr {
unsigned short int sa_family; /* Common data: address family and length. */
char sa_data[14]; /* Address data. */
};
int
socket(int domain, int type, int protocol);

View File

@ -118,19 +118,34 @@ enclave {
int ocall_pthread_rwlock_unlock([user_check]void *rwlock);
int ocall_get_errno();
int ocall_socket(int domain, int type, int protocol);
/* sockets */
int ocall_accept(int sockfd, [in, size=addr_size]void *addr,
[in, size=4] uint32_t *addrlen, uint32_t addr_size);
int ocall_bind(int sockfd, [in, size=addrlen]const void *addr,
uint32_t addrlen);
int ocall_connect(int sockfd, [in, size=addrlen]void *addr, uint32_t addrlen);
int ocall_getsockname(int sockfd, [in, size=addr_size]void *addr,
[in, out, size=4]uint32_t *addrlen, uint32_t addr_size);
int ocall_getsockopt(int sockfd, int level, int optname,
[out, size=val_buf_size]void *val_buf,
unsigned int val_buf_size,
[in, out, size=4]void *len_buf);
ssize_t ocall_sendmsg(int sockfd,
[in, size=msg_buf_size]void *msg_buf,
unsigned int msg_buf_size,
int flags);
int ocall_listen(int sockfd, int backlog);
int ocall_recv(int sockfd, [out, size=len]void *buf, size_t len, int flags);
ssize_t ocall_recvmsg(int sockfd,
[in, out, size=msg_buf_size]void *msg_buf,
unsigned int msg_buf_size,
int flags);
int ocall_send(int sockfd, [in, size=len]const void *buf, size_t len, int flags);
ssize_t ocall_sendmsg(int sockfd,
[in, size=msg_buf_size]void *msg_buf,
unsigned int msg_buf_size,
int flags);
int ocall_setsockopt(int sockfd, int level, int optname,
[in, size=optlen]void *optval,
unsigned int optlen);
int ocall_shutdown(int sockfd, int how);
int ocall_socket(int domain, int type, int protocol);
};
};

View File

@ -6,6 +6,8 @@
#include <sys/socket.h>
#include <stdint.h>
#include <stddef.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int
ocall_socket(int domain, int type, int protocol)
@ -72,4 +74,53 @@ int
ocall_shutdown(int sockfd, int how)
{
return shutdown(sockfd, how);
}
int
ocall_setsockopt(int sockfd, int level, int optname, void *optval,
unsigned int optlen)
{
return setsockopt(sockfd, level, optname, optval, optlen);
}
int
ocall_bind(int sockfd, const void *addr, uint32_t addrlen)
{
return bind(sockfd, (const struct sockaddr *)addr, addrlen);
}
int
ocall_getsockname(int sockfd, void *addr, uint32_t *addrlen, uint32_t addr_size)
{
return getsockname(sockfd, (struct sockaddr *)addr, addrlen);
}
int
ocall_listen(int sockfd, int backlog)
{
return listen(sockfd, backlog);
}
int
ocall_accept(int sockfd, void *addr, uint32_t *addrlen, uint32_t addr_size)
{
return accept(sockfd, (struct sockaddr *)addr, addrlen);
}
int
ocall_recv(int sockfd, void *buf, size_t len, int flags)
{
return recv(sockfd, buf, len, flags);
}
int
ocall_send(int sockfd, const void *buf, size_t len, int flags)
{
return send(sockfd, buf, len, flags);
}
int
ocall_connect(int sockfd, void *addr, uint32_t addrlen)
{
return connect(sockfd, (const struct sockaddr *)addr, addrlen);
}

View File

@ -66,6 +66,9 @@ cmake -DWAMR_BUILD_PLATFORM=linux -DWAMR_BUILD_TARGET=ARM
#### **Enable shared memory feature**
- **WAMR_BUILD_SHARED_MEMORY**=1/0, default to disable if not set
#### **Enable bulk memory feature**
- **WAMR_BUILD_BULK_MEMORY**=1/0, default to disable if not set
#### **Enable thread manager**
- **WAMR_BUILD_THREAD_MGR**=1/0, default to disable if not set

View File

@ -10,7 +10,7 @@ and `socket()`. Users can call those functions in WebAssembly code directly.
Those WebAssembly socket calls will be dispatched to the imported
functions and eventually will be implemented by host socket APIs.
This document introduces a way to support _Berkeley/Posix Socket APIs_ in
This document introduces a way to support the _Berkeley/POSIX Socket API_ in
WebAssembly code.
## Patch the native code
@ -24,7 +24,7 @@ native source code.
#endif
```
`__wasi__` is a Marco defined by WASI. The host compiler will not enable it.
`__wasi__` is a macro defined by WASI. The host compiler will not enable it.
## CMake files
@ -57,10 +57,25 @@ The _iwasm_ should be compiled with `WAMR_BUILD_LIBC_WASI=1`. By default, it is
enabled.
_iwasm_ accepts address ranges via an option, `--addr-pool`, to implement
the capability control. All IP address the WebAssebmly application may need to `bind()` or `connect()` should be announced first. Every IP address should be in CIRD notation.
the capability control. All IP address the WebAssembly application may need to `bind()` or `connect()`
should be announced first. Every IP address should be in CIRD notation.
```bash
$ iwasm --addr-pool=1.2.3.4/15,2.3.4.6/16 socket_example.wasm
```
Refer to [socket api sample](../samples/socket-api) for more details.
## Intel SGX support
WAMR also supports the socket API within Intel SGX enclaves.
The _iwasm_ should be compiled with `WAMR_BUILD_LIBC_WASI=1` and `WAMR_BUILD_LIB_PTHREAD=1`, which are enabled by default.
Similarly to running _iwasm_ outside of an enclave, the allowed address ranges are given via the option `--addr-pool`.
```bash
$ iwasm --addr-pool=1.2.3.4/15,2.3.4.6/16 socket_example.wasm
```
Refer to [socket api sample](../samples/socket-api) for the compilation of the Wasm applications and [_iwasm_ for Intel SGX](../product-mini/platforms/linux-sgx) for the Wasm runtime.

View File

@ -227,6 +227,10 @@ print_help()
printf(" --dir=<dir> Grant wasi access to the given host directories\n");
printf(" to the program, for example:\n");
printf(" --dir=<dir1> --dir=<dir2>\n");
printf(" --addr-pool= Grant wasi access to the given network addresses in\n");
printf(" CIRD notation to the program, seperated with ',',\n");
printf(" for example:\n");
printf(" --addr-pool=1.2.3.4/15,2.3.4.5/16\n");
printf(" --max-threads=n Set maximum thread number per cluster, default is 4\n");
return 1;
}
@ -550,9 +554,10 @@ app_instance_func(void *wasm_module_inst, const char *func_name, int app_argc,
static bool
set_wasi_args(void *wasm_module, const char **dir_list, uint32_t dir_list_size,
const char **env_list, uint32_t env_list_size, int stdinfd,
int stdoutfd, int stderrfd, char **argv, uint32_t argc)
int stdoutfd, int stderrfd, char **argv, uint32_t argc,
const char **addr_pool, uint32_t addr_pool_size)
{
uint64_t ecall_args[10];
uint64_t ecall_args[12];
ecall_args[0] = (uint64_t)(uintptr_t)wasm_module;
ecall_args[1] = (uint64_t)(uintptr_t)dir_list;
@ -564,9 +569,11 @@ set_wasi_args(void *wasm_module, const char **dir_list, uint32_t dir_list_size,
ecall_args[7] = stderrfd;
ecall_args[8] = (uint64_t)(uintptr_t)argv;
ecall_args[9] = argc;
ecall_args[10] = (uint64_t)(uintptr_t)addr_pool;
ecall_args[11] = addr_pool_size;
if (SGX_SUCCESS
!= ecall_handle_command(g_eid, CMD_SET_WASI_ARGS, (uint8_t *)ecall_args,
sizeof(uint64_t) * 10)) {
sizeof(uint64_t) * 12)) {
printf("Call ecall_handle_command() failed.\n");
}
@ -590,6 +597,8 @@ main(int argc, char *argv[])
uint32_t dir_list_size = 0;
const char *env_list[8] = { NULL };
uint32_t env_list_size = 0;
const char *addr_pool[8] = { NULL };
uint32_t addr_pool_size = 0;
uint32_t max_thread_num = 4;
if (enclave_init(&g_eid) < 0) {
@ -666,6 +675,26 @@ main(int argc, char *argv[])
return print_help();
}
}
/* TODO: parse the configuration file via --addr-pool-file */
else if (!strncmp(argv[0], "--addr-pool=", strlen("--addr-pool="))) {
/* like: --addr-pool=100.200.244.255/30 */
char *token = NULL;
if ('\0' == argv[0][12])
return print_help();
token = strtok(argv[0] + strlen("--addr-pool="), ",");
while (token) {
if (addr_pool_size >= sizeof(addr_pool) / sizeof(char *)) {
printf("Only allow max address number %d\n",
(int)(sizeof(addr_pool) / sizeof(char *)));
return -1;
}
addr_pool[addr_pool_size++] = token;
token = strtok(NULL, ";");
}
}
else if (!strncmp(argv[0], "--max-threads=", 14)) {
if (argv[0][14] == '\0')
return print_help();
@ -705,7 +734,8 @@ main(int argc, char *argv[])
/* Set wasi arguments */
if (!set_wasi_args(wasm_module, dir_list, dir_list_size, env_list,
env_list_size, 0, 1, 2, argv, argc)) {
env_list_size, 0, 1, 2, argv, argc, addr_pool,
addr_pool_size)) {
printf("%s\n", "set wasi arguments failed.\n");
goto fail3;
}
@ -771,6 +801,8 @@ wamr_pal_create_process(struct wamr_pal_create_process_args *args)
uint32_t dir_list_size = 0;
const char *env_list[8] = { NULL };
uint32_t env_list_size = 0;
const char *addr_pool[8] = { NULL };
uint32_t addr_pool_size = 0;
uint32_t max_thread_num = 4;
char *wasm_files[16];
void *wasm_module_inst[16];
@ -845,7 +877,7 @@ wamr_pal_create_process(struct wamr_pal_create_process_args *args)
/* Set wasi arguments */
if (!set_wasi_args(wasm_module, dir_list, dir_list_size, env_list,
env_list_size, stdinfd, stdoutfd, stderrfd, argv,
argc)) {
argc, addr_pool, addr_pool_size)) {
printf("%s\n", "set wasi arguments failed.\n");
unload_module(wasm_module);
free(wasm_file_buf);

View File

@ -50,6 +50,8 @@ typedef struct EnclaveModule {
uint32 wasi_dir_list_size;
char **wasi_env_list;
uint32 wasi_env_list_size;
char **wasi_addr_pool_list;
uint32 wasi_addr_pool_list_size;
char **wasi_argv;
uint32 wasi_argc;
bool is_xip_file;
@ -407,6 +409,8 @@ handle_cmd_set_wasi_args(uint64 *args, int32 argc)
char **wasi_argv = *(char ***)args++;
char *p, *p1;
uint32 wasi_argc = *(uint32 *)args++;
char **addr_pool_list = *(char ***)args++;
uint32 addr_pool_list_size = *(uint32 *)args++;
uint64 total_size = 0;
int32 i, str_len;
@ -414,6 +418,7 @@ handle_cmd_set_wasi_args(uint64 *args, int32 argc)
total_size += sizeof(char *) * (uint64)dir_list_size
+ sizeof(char *) * (uint64)env_list_size
+ sizeof(char *) * (uint64)addr_pool_list_size
+ sizeof(char *) * (uint64)wasi_argc;
for (i = 0; i < dir_list_size; i++) {
@ -424,6 +429,10 @@ handle_cmd_set_wasi_args(uint64 *args, int32 argc)
total_size += strlen(env_list[i]) + 1;
}
for (i = 0; i < addr_pool_list_size; i++) {
total_size += strlen(addr_pool_list[i]) + 1;
}
for (i = 0; i < wasi_argc; i++) {
total_size += strlen(wasi_argv[i]) + 1;
}
@ -436,7 +445,7 @@ handle_cmd_set_wasi_args(uint64 *args, int32 argc)
}
p1 = p + sizeof(char *) * dir_list_size + sizeof(char *) * env_list_size
+ sizeof(char *) * wasi_argc;
+ sizeof(char *) * addr_pool_list_size + sizeof(char *) * wasi_argc;
if (dir_list_size > 0) {
enclave_module->wasi_dir_list = (char **)p;
@ -462,6 +471,18 @@ handle_cmd_set_wasi_args(uint64 *args, int32 argc)
p += sizeof(char *) * env_list_size;
}
if (addr_pool_list_size > 0) {
enclave_module->wasi_addr_pool_list = (char **)p;
enclave_module->wasi_addr_pool_list_size = addr_pool_list_size;
for (i = 0; i < addr_pool_list_size; i++) {
enclave_module->wasi_addr_pool_list[i] = p1;
str_len = strlen(addr_pool_list[i]);
bh_memcpy_s(p1, str_len + 1, addr_pool_list[i], str_len + 1);
p1 += str_len + 1;
}
p += sizeof(char *) * addr_pool_list_size;
}
if (wasi_argc > 0) {
enclave_module->wasi_argv = (char **)p;
enclave_module->wasi_argc = wasi_argc;
@ -481,6 +502,11 @@ handle_cmd_set_wasi_args(uint64 *args, int32 argc)
(stdinfd != -1) ? stdinfd : 0, (stdoutfd != -1) ? stdoutfd : 1,
(stderrfd != -1) ? stderrfd : 2);
wasm_runtime_set_wasi_addr_pool(
enclave_module->module,
(const char **)enclave_module->wasi_addr_pool_list,
addr_pool_list_size);
*args_org = true;
}
#else

View File

@ -89,14 +89,17 @@ ExternalProject_Add(wasm-app
INSTALL_COMMAND ${CMAKE_COMMAND} -E copy
tcp_client.wasm ${CMAKE_CURRENT_SOURCE_DIR}/build
tcp_server.wasm ${CMAKE_CURRENT_SOURCE_DIR}/build
tcp_client.wasm.dump ${CMAKE_CURRENT_SOURCE_DIR}/build
tcp_server.wasm.dump ${CMAKE_CURRENT_SOURCE_DIR}/build
send_recv.wasm ${CMAKE_CURRENT_SOURCE_DIR}/build
)
add_executable(tcp_server ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src/tcp_server.c)
target_link_libraries(tcp_server pthread)
add_executable(tcp_client ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src/tcp_client.c)
add_executable(send_recv ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src/send_recv.c)
target_link_libraries(send_recv pthread)
############################################
## Build iwasm with wasi and pthread support
############################################

View File

@ -1,5 +1,4 @@
"socket-api" sample introduction
================================
# "socket-api" sample introduction
This sample demonstrates how to use WAMR socket-api to develop wasm network applications.
Two wasm applications are provided: tcp-server and tcp-client, and this sample demonstrates
@ -19,26 +18,30 @@ cmake ..
make
```
The file `tcp_server.wasm`, `tcp_client.wasm` and `iwasm` will be created.
And also file `tcp_server` and `tcp_client` of native version are created.
`iwasm` and three Wasm modules, `tcp_server.wasm`, `tcp_client.wasm`, `send_recv.wasm`
will be generated. And their corresponding native version, `tcp_server`,
`tcp_client`, `send_recv` are generated too.
Note that iwasm is built with libc-wasi and lib-pthread enabled.
> Note that iwasm is built with libc-wasi and lib-pthread enabled.
## Run workload
Start the tcp server, which opens port 1234 and waits for clients to connect.
```bash
cd build
./iwasm --addr-pool=0.0.0.0/15 tcp_server.wasm
```
Start the tcp client, which connects the server and receives message.
```bash
cd build
./iwasm --addr-pool=127.0.0.1/15 tcp_client.wasm
```
The output of client is like:
```bash
[Client] Create socket
[Client] Connect socket
@ -54,4 +57,29 @@ Say Hi from the Server
[Client] BYE
```
`send_recv.wasm` contains a thread as a server and a thread as a client. They
send and receive data via 127.0.0.1:1234.
```bash
$ ./iwasm --addr-pool=127.0.0.1/0 ./send_recv.wasm
```
The output is:
```bash
Server is online ...
Client is running...
Start receiving.
Start sending.
Send 106 bytes successfully!
Receive 106 bytes successlly!
Data:
The stars shine down
It brings us light
Light comes down
To make us paths
It watches us
And mourns for us
```
Refer to [socket api document](../../doc/socket_api.md) for more details.

View File

@ -78,3 +78,4 @@ endfunction()
compile_with_clang(tcp_server.c)
compile_with_clang(tcp_client.c)
compile_with_clang(send_recv.c)

View File

@ -0,0 +1,209 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include <arpa/inet.h>
#include <netinet/in.h>
#include <pthread.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#ifdef __wasi__
#include <wasi_socket_ext.h>
#endif
static pthread_mutex_t lock = { 0 };
static pthread_cond_t cond = { 0 };
static bool server_is_ready = false;
void *
run_as_server(void *arg)
{
int sock = -1, on = 1;
struct sockaddr_in addr = { 0 };
int addrlen = 0;
int new_sock = -1;
char *buf[] = {
"The stars shine down", "It brings us light", "Light comes down",
"To make us paths", "It watches us", "And mourns for us",
};
struct iovec iov[] = {
{ .iov_base = buf[0], .iov_len = strlen(buf[0]) + 1 },
{ .iov_base = buf[1], .iov_len = strlen(buf[1]) + 1 },
{ .iov_base = buf[2], .iov_len = strlen(buf[2]) + 1 },
{ .iov_base = buf[3], .iov_len = strlen(buf[3]) + 1 },
{ .iov_base = buf[4], .iov_len = strlen(buf[4]) + 1 },
{ .iov_base = buf[5], .iov_len = strlen(buf[5]) + 1 },
};
struct msghdr msg = { .msg_iov = iov, .msg_iovlen = 6 };
ssize_t send_len = 0;
pthread_mutex_lock(&lock);
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("Create a socket failed");
goto RETURN;
}
#ifndef __wasi__
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on))) {
perror("Setsockopt failed");
goto RETURN;
}
#endif
/* 0.0.0.0:1234 */
addr.sin_family = AF_INET;
addr.sin_port = htons(1234);
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
addrlen = sizeof(addr);
if (bind(sock, (struct sockaddr *)&addr, addrlen) < 0) {
perror("Bind failed");
goto UNLOCK_SHUTDOWN;
}
if (listen(sock, 0) < 0) {
perror("Listen failed");
goto UNLOCK_SHUTDOWN;
}
server_is_ready = true;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
printf("Server is online ... \n");
new_sock = accept(sock, (struct sockaddr *)&addr, (socklen_t *)&addrlen);
if (new_sock < 0) {
perror("Accept failed");
goto SHUTDOWN;
}
printf("Start sending. \n");
send_len = sendmsg(new_sock, &msg, 0);
if (send_len < 0) {
perror("Sendmsg failed");
goto SHUTDOWN;
}
printf("Send %ld bytes successfully!\n", send_len);
SHUTDOWN:
shutdown(sock, SHUT_RD);
return NULL;
UNLOCK_SHUTDOWN:
shutdown(sock, SHUT_RD);
RETURN:
pthread_mutex_unlock(&lock);
return NULL;
}
void *
run_as_client(void *arg)
{
int sock = -1;
struct sockaddr_in addr = { 0 };
char buf[256] = { 0 };
struct iovec iov = { .iov_base = buf, .iov_len = sizeof(buf) };
struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1 };
ssize_t recv_len = 0;
pthread_mutex_lock(&lock);
while (false == server_is_ready) {
pthread_cond_wait(&cond, &lock);
}
pthread_mutex_unlock(&lock);
printf("Client is running...\n");
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("Create a socket failed");
goto RETURN;
}
/* 127.0.0.1:1234 */
addr.sin_family = AF_INET;
addr.sin_port = htons(1234);
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("Connect failed");
goto UNLOCK_SHUTDOWN;
}
printf("Start receiving. \n");
recv_len = recvmsg(sock, &msg, 0);
if (recv_len < 0) {
perror("Recvmsg failed");
goto SHUTDOWN;
}
printf("Receive %ld bytes successlly!\n", recv_len);
printf("Data:\n");
uint8_t i = 0;
char *s = msg.msg_iov->iov_base;
for (i = 0; i < 6; i++) {
printf(" %s\n", s);
s += strlen(s) + 1;
}
SHUTDOWN:
shutdown(sock, SHUT_RD);
return NULL;
UNLOCK_SHUTDOWN:
shutdown(sock, SHUT_RD);
RETURN:
pthread_mutex_unlock(&lock);
return NULL;
}
int
main(int argc, char *argv[])
{
pthread_t cs[2] = { 0 };
uint8_t i = 0;
int ret = EXIT_SUCCESS;
if (pthread_mutex_init(&lock, NULL)) {
perror("Initialize mutex failed");
ret = EXIT_FAILURE;
goto RETURN;
}
if (pthread_cond_init(&cond, NULL)) {
perror("Initialize condition failed");
ret = EXIT_FAILURE;
goto DESTROY_MUTEX;
}
if (pthread_create(&cs[0], NULL, run_as_server, NULL)) {
perror("Create a server thread failed");
ret = EXIT_FAILURE;
goto DESTROY_COND;
}
if (pthread_create(&cs[1], NULL, run_as_client, NULL)) {
perror("Create a client thread failed");
ret = EXIT_FAILURE;
goto DESTROY_COND;
}
for (i = 0; i < 2; i++) {
pthread_join(cs[i], NULL);
}
DESTROY_COND:
pthread_cond_destroy(&cond);
DESTROY_MUTEX:
pthread_mutex_destroy(&lock);
RETURN:
return ret;
}