Skip to content
This repository has been archived by the owner on Dec 26, 2022. It is now read-only.

Commit

Permalink
feat(endpoint): Consolidate by merging Endpoint subproject
Browse files Browse the repository at this point in the history
Endpoint aims for solving issues on low level endpoint devices.
Low level devices can request trustable blockchain services with
`endpoint` of tangle-accelerator. For more information, README under
`docs/endpoint.md` would provide more detailed information.

The mbedtls and http-parser submodule are added into third_party/.
Add "//third_party:mbedtls" and "//third_party/http-parser" after `deps`
if you need to use them.

The PEM directory contains the private key and certificate for building
system. See pem/README.md to change the certificate.
  • Loading branch information
howjmay authored and splasky committed Apr 30, 2020
1 parent 1bf3732 commit 7947daa
Show file tree
Hide file tree
Showing 37 changed files with 1,874 additions and 3 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,6 @@ docs/html/

# Python
__pycache__/

# Certificate for build system
pem/*.inc
6 changes: 6 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,9 @@
[submodule "third_party/mosquitto"]
path = third_party/mosquitto
url = https://github.com/eclipse/mosquitto.git
[submodule "third_party/http-parser"]
path = third_party/http-parser
url = https://github.com/nodejs/http-parser.git
[submodule "third_party/mbedtls"]
path = third_party/mbedtls
url = https://github.com/ARMmbed/mbedtls.git
37 changes: 34 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,17 @@ DCURL_DIR := third_party/dcurl
DCURL_LIB := $(DCURL_DIR)/build/libdcurl.so
MOSQUITTO_DIR := third_party/mosquitto
MOSQUITTO_LIB := $(MOSQUITTO_DIR)/lib/libmosquitto.so.1
DEPS += $(DCURL_LIB)
MBEDTLS_DIR := third_party/mbedtls
MBEDTLS_LIB := $(MBEDTLS_PATH)/library/libmbedx509.so $(MBEDTLS_PATH)/library/libmbedtls.so $(MBEDTLS_PATH)/library/libmbedcrypto.so
HTTPPARSER_DIR := third_party/http-parser
HTTPPARSER_LIB := $(HTTPPARSER_DIR)/libhttp_parser.so
PEM_DIR = pem
DEPS += $(DCURL_LIB) $(HTTPPARSER_LIB) $(MBEDTLS_LIB)
PEM := $(PEM_DIR)/cert.pem

all: $(DEPS)
all: $(DEPS) cert

.PHONY: $(DCURL_LIB) $(MOSQUITTO_LIB)
.PHONY: $(DCURL_LIB) $(MOSQUITTO_LIB) cert check_pem

$(DCURL_LIB): $(DCURL_DIR)
git submodule update --init $^
Expand All @@ -21,9 +27,34 @@ $(MOSQUITTO_LIB): $(MOSQUITTO_DIR)
@echo
$(MAKE) -C $^ WITH_DOCS=no

$(HTTPPARSER_LIB): $(HTTPPARSER_DIR)
git submodule update --init $^
$(MAKE) -C $^ library

$(MBEDTLS_LIB): $(MBEDTLS_DIR)
git submodule update --init $^
$(MAKE) -C $^ SHARED=1 lib

cert: check_pem
@xxd -i $(PEM) > $(PEM_DIR)/ca_crt.inc
@sed -E \
-e 's/(unsigned char)(.*)(\[\])(.*)/echo "\1 ca_crt_pem\3\4"/ge' \
-e 's/(unsigned int)(.*)(=)(.*)/echo "\1 ca_crt_pem_len \3\4"/ge' \
-e 's/^unsigned/static &/' \
-e 's/(.*)(pem_len = )([0-9]+)(.*)/echo "\1\2$$((\3+1))\4"/ge' \
-e 's/(0[xX][[[:xdigit:]]+)$$/\1, 0x0/g' \
-i $(PEM_DIR)/ca_crt.inc
check_pem:
ifndef PEM
$(error PEM is not set)
endif

clean:
$(MAKE) -C $(DCURL_DIR) clean
$(MAKE) -C $(MOSQUITTO_DIR) clean
$(MAKE) -C $(HTTPPARSER_DIR) clean
$(MAKE) -C $(MBEDTLS_DIR) clean


distclean: clean
$(RM) -r $(DCURL_DIR)
Expand Down
5 changes: 5 additions & 0 deletions common/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,8 @@ cc_library(
"@entangled//common/model:transaction",
],
)

cc_library(
name = "defined_error",
hdrs = ["defined_error.h"],
)
41 changes: 41 additions & 0 deletions common/defined_error.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright (C) 2019-2020 BiiLabs Co., Ltd. and Contributors
* All Rights Reserved.
* This is free software; you can redistribute it and/or modify it under the
* terms of the MIT license. A copy of the license can be found in the file
* "LICENSE" at the root of this distribution.
*/

#ifndef COMMON_DEFINED_ERROR_H
#define COMMON_DEFINED_ERROR_H

#ifdef __cplusplus
extern "C" {
#endif

#define HTTP_OK 200 /**< HTTP status codes */

/* FIXME:The status should be integrated into common/ta_error.h */
/* status code */
typedef enum {
RET_OK, /**< success */
RET_WRITE_ERROR, /**< write error */
RET_OOM, /**< out of memory */
RET_HTTP_INIT, /**< failed on HTTP init */
RET_HTTP_CERT, /**< failed on x509 cert parse */
RET_HTTP_CONNECT, /**< failed on HTTP initial connection */
RET_HTTP_SSL, /**< failed on setting ssl config */
RET_DEVICE_INIT, /**< initialize device error */
RET_DEVICE_FINI, /**< finalize device error */
RET_UART_INIT, /**< initialize uart error */
RET_OVERFLOW, /**< overflow error */
RET_NOT_FOUND, /**< item not found error */
RET_UNAVAILABLE, /**< item not available */
RET_FAULT /**< some other fault */
} endpoint_retcode_t;

#ifdef __cplusplus
}
#endif

#endif // COMMON_DEFINED_ERROR_H
95 changes: 95 additions & 0 deletions docs/endpoint-hal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# Hardware Abstract Layer(HAL) for Endpoint

Hardware Abstract Layer(HAL) defines a standard interface for hardware vendors to implement new device, which enables Tangle-accelerator to be aware of lower-level driver implementations. HAL provides operators such as UART, GPIO, secure storage and other low-level operators. The endpoint is a daemon, offering monitor for the device and being able to send message to Tangle-Accelerator. HAL layer lets the user only need to implement their device operators from abstract interface which is defined inside `device.h` but not need to know how endpoint works.

## How to implement new device

Create a directory for the new device under `devices`.
```
$mkdir -p devices/mydevice
```
* Create `impl.c` and `Makefile` under the new device directory.
* Include `device.h` into the new device header or the new device source file.

Here are some operations needed to be implemented for new device:
* device_operations
* init : initialize device
* fini : finalize device
* get_key : get device key
* get_device_id : get device id(IMEI or other identifier)
* uart_operations
* init : initialize uart
* write : write command to uart device
* read : read from uart device
* clean : flush buffer
* secure_store_operations
* init : initialize secure storage
* write : write item to secure storage
* read : read item from secure storage
* delete : delete item inside secure storage

Here are the functions needed to be registered/unregistered inside `impl.c`:
* register_device : register device on startup
* unregister_device : unregister device
* DECLARE_DEVICE : this must be declared inside `impl.c`

Add the new device into `hal/Makefile`:

* Append the device object to DEVICE_OBJS
* Add the new device build target(mydevice.o)
```
DEVICE_OBJS = wp7702.o emulator.o device.o mydevice.o
export DEVICE_OBJS
all: $(DEVICE_OBJS)
mydevice.o: device.o
$(MAKE) -C ../devices/mydevice
```

Implement a new device which is created under `devices` directory, and edit the Makefile. The example device is named as `mydevice`:
```
all: mydevice.o
mydevice.o: impl.c
$(CC) $(CFLAGS) $(INCLUDES) -c $^ -o $@
```
`$(CC)`,`$(CFLAGS)` and `$(INCLUDES)` are specified by build system. `CC` sets the default compiler for the project. `CFLAGS` are the default flags that would be passed to default compiler during compiling time. `INCLUDES` flag includes headers inside sub-projects and third-party libraries. You can also modify these flags inside your device's Makefile.

impl.c
```c
#include "device.h"

static inline void register_emulator(void);
static inline void unregister_emulator(void);

static struct device_operations emulator_ops = {.init = &emulator_init,
.fini = &emulator_release,
.get_key = &emulator_get_key,
.get_device_id = &emulator_get_device_id};

static struct uart_operations emulator_uart = {
.init = &uart_init, .write = &uart_write, .read = &uart_read, .clean = &uart_clean};

static struct device_type emulator_device_type = {
.name = "emulator", .op = &emulator_ops, .uart = &emulator_uart, .sec_ops = &emulator_sec_ops};

static inline void register_emulator(void) {
int err = register_device(&emulator_device_type);
if (err) LOG_ERROR("register emulator device error:%d", err);
}

static inline void unregister_emulator(void) {
int err = unregister_device(&emulator_device_type);
if (err) LOG_ERROR("unregister device emulator error:%d", err);
}

static int emulator_init(void) {
register_emulator();
return DEVICE_OK;
}

static void emulator_release(void) { unregister_emulator(); }

// must be declared at the end of impl.c
DECLARE_DEVICE(emulator);
```
12 changes: 12 additions & 0 deletions docs/endpoint.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Endpoint
The endpoint is one of the components provided by Tangle-accelerator, running on a resource-constrained network connectivity module. The embedded devices can send messages to blockchain network (Tangle) with a connectivity module loaded endpoint. The message would be transmitted to connectivity module through UART. Message would be encrypted and send to tangle.

# Streaming Message Channel Implementation
The encrypted message would be sent to Tangle with a streaming message channel API. The streaming message channel API would ensure the order of messages in the channel. The user who wants to fetch/send message to Tangle needs to provide `data_id`, `key` and `protocol` to identify a specific message.
A message sent by endpoint needs to be encrypted locally, which avoids message being peeked and modified.

# How to use
```
$ bazel build //endpoint:wp7702
$ bazel build //endpoint:sim
```
30 changes: 30 additions & 0 deletions endpoint/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
cc_library(
name = "endpoint",
srcs = ["endpoint.c"],
hdrs = ["endpoint.h"],
defines = [
"TA_HOST=\"tangle-accel.biilabs.io\"",
"TA_PORT=\"443\"",
"TA_SSL_SEED=\"nonce\"",
],
visibility = ["//visibility:public"],
deps = [
"//common:defined_error",
"//utils:cipher",
"//utils:https",
"//utils:text_serializer",
"//utils:tryte_byte_conv",
],
)

cc_test(
name = "test_endpoint",
srcs = [
"test_endpoint.c",
],
deps = [
":endpoint",
"//common",
"//tests:test_define",
],
)
85 changes: 85 additions & 0 deletions endpoint/endpoint.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* Copyright (C) 2019-2020 BiiLabs Co., Ltd. and Contributors
* All Rights Reserved.
* This is free software; you can redistribute it and/or modify it under the
* terms of the MIT license. A copy of the license can be found in the file
* "LICENSE" at the root of this distribution.
*/

#include "endpoint.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "http_parser.h"
#include "utils/cipher.h"
#include "utils/connectivity/conn_http.h"
#include "utils/https.h"
#include "utils/text_serializer.h"
#include "utils/tryte_byte_conv.h"

#define STRINGIZE(x) #x
#define STRINGIZE_VALUE_OF(x) STRINGIZE(x)

const char* HOST = STRINGIZE_VALUE_OF(TA_HOST);
const char* PORT = STRINGIZE_VALUE_OF(TA_PORT);
const char* SSL_SEED = STRINGIZE_VALUE_OF(TA_SSL_SEED);

#define REQ_BODY \
"{\"value\": %d, \"message\": \"%s\", \"message_format\": \"%s\", \"tag\": \"%s\", \"address\": \"%s\"}\r\n\r\n"

#define SEND_TRANSACTION_API "transaction/"

endpoint_retcode_t send_transaction_information(int value, const char* message, const char* message_fmt,
const char* tag, const char* address, const char* next_address,
const uint8_t* private_key, const char* device_id, uint8_t* iv) {
char tryte_msg[MAX_MSG_LEN] = {0};
char msg[MAX_MSG_LEN] = {0};
char ciphertext[MAX_MSG_LEN] = {0};
char req_body[MAX_MSG_LEN] = {0};
char raw_msg[MAX_MSG_LEN] = {0};

int ret = snprintf(raw_msg, MAX_MSG_LEN, "%s:%s", address, message);
if (ret < 0) {
// FIXME: Replace to default logger
fprintf(stderr, "message is to long");
return RET_FAULT;
}

size_t msg_len = 0;
ta_cipher_ctx encrypt_ctx = {.plaintext = raw_msg,
.plaintext_len = ret,
.ciphertext = ciphertext,
.ciphertext_len = MAX_MSG_LEN,
.device_id = device_id,
.iv = {0},
.key = private_key,
.keybits = TA_AES_KEY_BITS};
memcpy(encrypt_ctx.iv, iv, AES_IV_SIZE);
ret = aes_encrypt(&encrypt_ctx);
memcpy(iv, encrypt_ctx.iv, AES_IV_SIZE);

// FIXME: Replace to default logger
if (ret != RET_OK) {
fprintf(stderr, "%s\n", "encrypt msg error");
return ret;
}
serialize_msg(iv, encrypt_ctx.ciphertext_len, encrypt_ctx.ciphertext, msg, &msg_len);
bytes_to_trytes((const unsigned char*)msg, msg_len, tryte_msg);

memset(req_body, 0, sizeof(char) * MAX_MSG_LEN);

ret = snprintf(req_body, MAX_MSG_LEN, REQ_BODY, value, tryte_msg, message_fmt, tag, address);
if (ret < 0) {
// FIXME: Replace to default logger
fprintf(stderr, "message is to long");
return RET_FAULT;
}

if (send_https_msg(HOST, PORT, SEND_TRANSACTION_API, req_body, MAX_MSG_LEN, SSL_SEED) != RET_OK) {
// FIXME: Replace to default logger
fprintf(stderr, "%s\n", "send http message error");
return RET_FAULT;
}

return RET_OK;
}
39 changes: 39 additions & 0 deletions endpoint/endpoint.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright (C) 2019-2020 BiiLabs Co., Ltd. and Contributors
* All Rights Reserved.
* This is free software; you can redistribute it and/or modify it under the
* terms of the MIT license. A copy of the license can be found in the file
* "LICENSE" at the root of this distribution.
*/

#ifndef ENDPOINT_H
#define ENDPOINT_H

#define ADDR_LEN 81
#define MAX_MSG_LEN 1024

#include <stdint.h>
#include "common/defined_error.h"

/**
* @brief Send transaction information to tangle accelerator
*
* @param[in] value Amount of the IOTA currency will be sent
* @param[in] message Message of the transaction in Trytes format
* @param[in] message_fmt Treating message field as specified format. Can be one of `ascii` or `trytes`. Default:
* `ascii`
* @param[in] tag Tag of transactions into several classifications. Tag is 27-trytes characters, e.g.
* POWEREDBYTANGLEACCELERATOR9
* @param[in] address Address of the receiver where IOTA currency will be sent to
* @param[in] next_address Next address to be sent inside message
* @param[in] private_key Private key from device
* @param[in] device_id Device id from device
* @param[in/out] iv Initialization vector, must be read/write. The length of iv must be AES_IV_SIZE @see #ta_cipher_ctx
*
* @return #endpoint_retcode_t
*/
endpoint_retcode_t send_transaction_information(const int value, const char* message, const char* message_fmt,
const char* tag, const char* address, const char* next_address,
const uint8_t* private_key, const char* device_id, uint8_t* iv);

#endif // ENDPOINT_H
Loading

0 comments on commit 7947daa

Please sign in to comment.