mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2025-02-06 23:15:16 +00:00
![Wenyong Huang](/assets/img/avatar_default.png)
Implement XIP (Execution In Place) feature for AOT mode to enable running the AOT code inside AOT file directly, without memory mapping the executable memory for AOT code and applying relocations for text section. Developer can use wamrc with "--enable-indirect-mode --disable-llvm-intrinsics" flags to generate the AOT file and run iwasm with "--xip" flag. Known issues: there might still be some relocations in the text section which access the ".rodata" like sections. And also enable ARC target support for both interpreter mode and AOT mode. Signed-off-by: Wenyong Huang <wenyong.huang@intel.com>
491 lines
12 KiB
C
491 lines
12 KiB
C
/*
|
|
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
|
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
|
|
#include "bi-inc/shared_utils.h"
|
|
|
|
/* Serialization of request and response message
|
|
*
|
|
* Choices:
|
|
* We considered a few options:
|
|
* 1. coap
|
|
* 2. flatbuffer
|
|
* 3. cbor
|
|
* 4. attr-containers of our own
|
|
* 5. customized serialization for request/response
|
|
*
|
|
* Now we choose the #5 mainly because we need to quickly get the URL for dispatching
|
|
* and sometimes we want to change the URL in the original packet. the request format:
|
|
* fixed part: version: (1 byte), code (1 byte), fmt(2 byte), mid (4 bytes), sender_id(4 bytes), url_len(2 bytes), payload_len(4bytes)
|
|
* dynamic part: url (bytes in url_len), payload
|
|
*
|
|
* response format:
|
|
* fixed part: (1 byte), code (1 byte), fmt(2 byte), mid (4 bytes), sender_id(4 bytes), payload_len(4bytes)
|
|
* dynamic part: payload
|
|
*/
|
|
#define REQUES_PACKET_VER 1
|
|
#define REQUEST_PACKET_FIX_PART_LEN 18
|
|
#define REQUEST_PACKET_URL_OFFSET REQUEST_PACKET_FIX_PART_LEN
|
|
#define REQUEST_PACKET_URL_LEN *((uint16*)((char*) buffer + 12)) /* to ensure little endian */
|
|
#define REQUEST_PACKET_PAYLOAD_LEN *((uint32*)((char*) buffer + 14)) /* to ensure little endian */
|
|
#define REQUEST_PACKET_URL(buffer) ((char*) buffer + REQUEST_PACKET_URL_OFFSET)
|
|
#define REQUEST_PACKET_PAYLOAD(buffer) ((char*) buffer + REQUEST_PACKET_URL_OFFSET + REQUEST_PACKET_URL_LEN(buffer))
|
|
|
|
#define RESPONSE_PACKET_FIX_PART_LEN 16
|
|
|
|
char *
|
|
pack_request(request_t *request, int *size)
|
|
{
|
|
int url_len = strlen(request->url) + 1;
|
|
int len = REQUEST_PACKET_FIX_PART_LEN + url_len + request->payload_len;
|
|
uint16 u16;
|
|
uint32 u32;
|
|
char *packet;
|
|
|
|
if ((packet = (char*) WA_MALLOC(len)) == NULL)
|
|
return NULL;
|
|
|
|
/* TODO: ensure little endian for words and dwords */
|
|
*packet = REQUES_PACKET_VER;
|
|
*((uint8*) (packet + 1)) = request->action;
|
|
|
|
u16 = htons(request->fmt);
|
|
memcpy(packet + 2, &u16, 2);
|
|
|
|
u32 = htonl(request->mid);
|
|
memcpy(packet + 4, &u32, 4);
|
|
|
|
u32 = htonl(request->sender);
|
|
memcpy(packet + 8, &u32, 4);
|
|
|
|
u16 = htons(url_len);
|
|
memcpy(packet + 12, &u16, 2);
|
|
|
|
u32 = htonl(request->payload_len);
|
|
memcpy(packet + 14, &u32, 4);
|
|
|
|
strcpy(packet + REQUEST_PACKET_URL_OFFSET, request->url);
|
|
memcpy(packet + REQUEST_PACKET_URL_OFFSET + url_len, request->payload,
|
|
request->payload_len);
|
|
|
|
*size = len;
|
|
return packet;
|
|
}
|
|
|
|
void
|
|
free_req_resp_packet(char *packet)
|
|
{
|
|
WA_FREE(packet);
|
|
}
|
|
|
|
request_t *
|
|
unpack_request(char *packet, int size, request_t *request)
|
|
{
|
|
uint16 url_len, u16;
|
|
uint32 payload_len, u32;
|
|
|
|
if (*packet != REQUES_PACKET_VER) {
|
|
return NULL;
|
|
}
|
|
if (size < REQUEST_PACKET_FIX_PART_LEN) {
|
|
return NULL;
|
|
}
|
|
|
|
memcpy(&u16, packet + 12, 2);
|
|
url_len = ntohs(u16);
|
|
|
|
memcpy(&u32, packet + 14, 4);
|
|
payload_len = ntohl(u32);
|
|
|
|
if (size != (REQUEST_PACKET_FIX_PART_LEN + url_len + payload_len)) {
|
|
return NULL;
|
|
}
|
|
|
|
if (*(packet + REQUEST_PACKET_FIX_PART_LEN + url_len - 1) != 0) {
|
|
return NULL;
|
|
}
|
|
|
|
request->action = *((uint8*) (packet + 1));
|
|
|
|
memcpy(&u16, packet + 2, 2);
|
|
request->fmt = ntohs(u16);
|
|
|
|
memcpy(&u32, packet + 4, 4);
|
|
request->mid = ntohl(u32);
|
|
|
|
memcpy(&u32, packet + 8, 4);
|
|
request->sender = ntohl(u32);
|
|
|
|
request->payload_len = payload_len;
|
|
request->url = REQUEST_PACKET_URL(packet);
|
|
|
|
if (payload_len > 0)
|
|
request->payload = packet + REQUEST_PACKET_URL_OFFSET + url_len;
|
|
else
|
|
request->payload = NULL;
|
|
|
|
return request;
|
|
}
|
|
|
|
char *
|
|
pack_response(response_t *response, int *size)
|
|
{
|
|
int len = RESPONSE_PACKET_FIX_PART_LEN + response->payload_len;
|
|
uint16 u16;
|
|
uint32 u32;
|
|
char *packet;
|
|
|
|
if ((packet = (char*) WA_MALLOC(len)) == NULL)
|
|
return NULL;
|
|
|
|
/* TODO: ensure little endian for words and dwords */
|
|
*packet = REQUES_PACKET_VER;
|
|
*((uint8*) (packet + 1)) = response->status;
|
|
|
|
u16 = htons(response->fmt);
|
|
memcpy(packet + 2, &u16, 2);
|
|
|
|
u32 = htonl(response->mid);
|
|
memcpy(packet + 4, &u32, 4);
|
|
|
|
u32 = htonl(response->reciever);
|
|
memcpy(packet + 8, &u32, 4);
|
|
|
|
u32 = htonl(response->payload_len);
|
|
memcpy(packet + 12, &u32, 4);
|
|
|
|
memcpy(packet + RESPONSE_PACKET_FIX_PART_LEN, response->payload,
|
|
response->payload_len);
|
|
|
|
*size = len;
|
|
return packet;
|
|
}
|
|
|
|
response_t *
|
|
unpack_response(char *packet, int size, response_t *response)
|
|
{
|
|
uint16 u16;
|
|
uint32 payload_len, u32;
|
|
|
|
if (*packet != REQUES_PACKET_VER)
|
|
return NULL;
|
|
|
|
if (size < RESPONSE_PACKET_FIX_PART_LEN)
|
|
return NULL;
|
|
|
|
memcpy(&u32, packet + 12, 4);
|
|
payload_len = ntohl(u32);
|
|
if (size != (RESPONSE_PACKET_FIX_PART_LEN + payload_len))
|
|
return NULL;
|
|
|
|
response->status = *((uint8*) (packet + 1));
|
|
|
|
memcpy(&u16, packet + 2, 2);
|
|
response->fmt = ntohs(u16);
|
|
|
|
memcpy(&u32, packet + 4, 4);
|
|
response->mid = ntohl(u32);
|
|
|
|
memcpy(&u32, packet + 8, 4);
|
|
response->reciever = ntohl(u32);
|
|
|
|
response->payload_len = payload_len;
|
|
if (payload_len > 0)
|
|
response->payload = packet + RESPONSE_PACKET_FIX_PART_LEN;
|
|
else
|
|
response->payload = NULL;
|
|
|
|
return response;
|
|
}
|
|
|
|
request_t *
|
|
clone_request(request_t *request)
|
|
{
|
|
/* deep clone */
|
|
request_t *req = (request_t *) WA_MALLOC(sizeof(request_t));
|
|
if (req == NULL)
|
|
return NULL;
|
|
|
|
memset(req, 0, sizeof(*req));
|
|
req->action = request->action;
|
|
req->fmt = request->fmt;
|
|
req->url = wa_strdup(request->url);
|
|
req->sender = request->sender;
|
|
req->mid = request->mid;
|
|
|
|
if (req->url == NULL)
|
|
goto fail;
|
|
|
|
req->payload_len = request->payload_len;
|
|
|
|
if (request->payload_len) {
|
|
req->payload = (char *)WA_MALLOC(request->payload_len);
|
|
if (!req->payload)
|
|
goto fail;
|
|
memcpy(req->payload, request->payload, request->payload_len);
|
|
}
|
|
else {
|
|
/* when payload_len is 0, the payload may be used for
|
|
carrying some handle or integer */
|
|
req->payload = request->payload;
|
|
}
|
|
|
|
return req;
|
|
|
|
fail:
|
|
request_cleaner(req);
|
|
return NULL;
|
|
}
|
|
|
|
void
|
|
request_cleaner(request_t *request)
|
|
{
|
|
if (request->url != NULL)
|
|
WA_FREE(request->url);
|
|
if (request->payload != NULL && request->payload_len > 0)
|
|
WA_FREE(request->payload);
|
|
|
|
WA_FREE(request);
|
|
}
|
|
|
|
void
|
|
response_cleaner(response_t *response)
|
|
{
|
|
if (response->payload != NULL && response->payload_len > 0)
|
|
WA_FREE(response->payload);
|
|
|
|
WA_FREE(response);
|
|
}
|
|
|
|
response_t *
|
|
clone_response(response_t *response)
|
|
{
|
|
response_t *clone = (response_t *)WA_MALLOC(sizeof(response_t));
|
|
|
|
if (clone == NULL)
|
|
return NULL;
|
|
|
|
memset(clone, 0, sizeof(*clone));
|
|
clone->fmt = response->fmt;
|
|
clone->mid = response->mid;
|
|
clone->status = response->status;
|
|
clone->reciever = response->reciever;
|
|
clone->payload_len = response->payload_len;
|
|
if (clone->payload_len) {
|
|
clone->payload = (char *) WA_MALLOC(response->payload_len);
|
|
if (!clone->payload)
|
|
goto fail;
|
|
memcpy(clone->payload, response->payload, response->payload_len);
|
|
}
|
|
else {
|
|
/* when payload_len is 0, the payload may be used for
|
|
carrying some handle or integer */
|
|
clone->payload = response->payload;
|
|
}
|
|
return clone;
|
|
|
|
fail:
|
|
response_cleaner(clone);
|
|
return NULL;
|
|
}
|
|
|
|
response_t *
|
|
set_response(response_t *response, int status, int fmt,
|
|
const char *payload, int payload_len)
|
|
{
|
|
response->payload = (void *)payload;
|
|
response->payload_len = payload_len;
|
|
response->status = status;
|
|
response->fmt = fmt;
|
|
return response;
|
|
}
|
|
|
|
response_t *
|
|
make_response_for_request(request_t *request,
|
|
response_t *response)
|
|
{
|
|
response->mid = request->mid;
|
|
response->reciever = request->sender;
|
|
|
|
return response;
|
|
}
|
|
|
|
static unsigned int mid = 0;
|
|
|
|
request_t *
|
|
init_request(request_t *request, char *url, int action, int fmt,
|
|
void *payload, int payload_len)
|
|
{
|
|
request->url = url;
|
|
request->action = action;
|
|
request->fmt = fmt;
|
|
request->payload = payload;
|
|
request->payload_len = payload_len;
|
|
request->mid = ++mid;
|
|
|
|
return request;
|
|
}
|
|
|
|
/*
|
|
check if the "url" is starting with "leading_str"
|
|
return: 0 - not match; >0 - the offset of matched url, include any "/" at the end
|
|
notes:
|
|
1. it ensures the leading_str "/abc" can pass "/abc/cde" and "/abc/, but fail "/ab" and "/abcd".
|
|
leading_str "/abc/" can pass "/abc"
|
|
2. it omit the '/' at the first char
|
|
3. it ensure the leading_str "/abc" can pass "/abc?cde
|
|
*/
|
|
|
|
int
|
|
check_url_start(const char *url, int url_len, const char *leading_str)
|
|
{
|
|
int offset = 0;
|
|
if (*leading_str == '/')
|
|
leading_str++;
|
|
if (url_len > 0 && *url == '/') {
|
|
url_len--;
|
|
url++;
|
|
offset++;
|
|
}
|
|
|
|
int len = strlen(leading_str);
|
|
if (len == 0)
|
|
return 0;
|
|
|
|
/* ensure leading_str not end with "/" */
|
|
if (leading_str[len - 1] == '/') {
|
|
len--;
|
|
if (len == 0)
|
|
return 0;
|
|
}
|
|
|
|
/* equal length */
|
|
if (url_len == len) {
|
|
if (memcmp(url, leading_str, url_len) == 0) {
|
|
return (offset + len);
|
|
}
|
|
else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (url_len < len)
|
|
return 0;
|
|
else if (memcmp(url, leading_str, len) != 0)
|
|
return 0;
|
|
else if (url[len] != '/' && url[len] != '?')
|
|
return 0;
|
|
else
|
|
return (offset + len + 1);
|
|
}
|
|
|
|
// * @pattern:
|
|
// * sample 1: /abcd, match /abcd only
|
|
// * sample 2: /abcd/ match match "/abcd" and "/abcd/*"
|
|
// * sample 3: /abcd*, match any url started with "/abcd"
|
|
// * sample 4: /abcd/*, exclude "/abcd"
|
|
|
|
bool
|
|
match_url(char *pattern, char *matched)
|
|
{
|
|
if (*pattern == '/')
|
|
pattern++;
|
|
if (*matched == '/')
|
|
matched++;
|
|
|
|
int matched_len = strlen(matched);
|
|
if (matched_len == 0)
|
|
return false;
|
|
|
|
if (matched[matched_len - 1] == '/') {
|
|
matched_len--;
|
|
if (matched_len == 0)
|
|
return false;
|
|
}
|
|
|
|
int len = strlen(pattern);
|
|
if (len == 0)
|
|
return false;
|
|
|
|
if (pattern[len - 1] == '/') {
|
|
len--;
|
|
if (strncmp(pattern, matched, len) != 0)
|
|
return false;
|
|
|
|
if (len == matched_len)
|
|
return true;
|
|
|
|
if (matched_len > len && matched[len] == '/')
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
else if (pattern[len - 1] == '*') {
|
|
if (pattern[len - 2] == '/') {
|
|
if (strncmp(pattern, matched, len - 1) == 0)
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
else {
|
|
return (strncmp(pattern, matched, len - 1) == 0);
|
|
}
|
|
}
|
|
else {
|
|
return (strcmp(pattern, matched) == 0);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* get the value of the key from following format buffer:
|
|
* key1=value1;key2=value2;key3=value3
|
|
*/
|
|
char *
|
|
find_key_value(char *buffer, int buffer_len, char *key, char *value,
|
|
int value_len, char delimiter)
|
|
{
|
|
char *p = buffer;
|
|
int remaining = buffer_len;
|
|
int key_len = strlen(key);
|
|
|
|
while (*p != 0 && remaining > 0) {
|
|
while (*p == ' ' || *p == delimiter) {
|
|
p++;
|
|
remaining--;
|
|
}
|
|
|
|
if (remaining <= key_len)
|
|
return NULL;
|
|
|
|
/* find the key */
|
|
if (0 == strncmp(p, key, key_len) && p[key_len] == '=') {
|
|
p += (key_len + 1);
|
|
remaining -= (key_len + 1);
|
|
char * v = value;
|
|
memset(value, 0, value_len);
|
|
value_len--; /* ensure last char is 0 */
|
|
while (*p != delimiter && remaining > 0 && value_len > 0) {
|
|
*v++ = *p++;
|
|
remaining--;
|
|
value_len--;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
/* goto next key */
|
|
while (*p != delimiter && remaining > 0) {
|
|
p++;
|
|
remaining--;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|