/*
* Copyright 2019 TP-Link Technologies Co., Ltd. All rights reserved.
*
*
*/
#include "nano_bus.h"
#include "nano_switch.h"
#include "nano_loop.h"
//#define NANO_BUS_DEBUG
#ifdef NANO_BUS_DEBUG
#define NANO_BUS_LOG(format, ...) OSAL_PRINTF("%s:%d: "format, __FUNCTION__, __LINE__, ##__VA_ARGS__)
#else
#define NANO_BUS_LOG(format, ...)
#endif
#define NANO_BUS_DAEMON_ADDR 0x1
enum {
NANO_BUS_MSG_REQUEST,
NANO_BUS_MSG_RESPONSE,
NANO_BUS_MSG_EVENT,
};
typedef struct _nano_bus_request_t {
struct list_head list;
SH_INT32 id;
nano_bus_request_cb_t cb;
void *priv;
SH_BOOL done;
SH_BOOL async;
SH_UINT64 time;
} nano_bus_request_t;
typedef struct _nano_busd_event_node_t {
struct list_head list;
SH_CHAR *name;
SH_INT32 ref_count;
} nano_busd_event_node_t;
typedef struct _nano_busd_event_t {
struct list_head list;
struct list_head evts;
SH_UINT8 addr;
} nano_busd_event_t;
typedef struct _nano_busd_context_t {
struct list_head objs;
struct list_head evts;
struct nano_loop_context *loop_ctx;
struct nano_loop_fd sock;
struct nano_loop_timeout timer;
} nano_busd_context_t;
static void nano_bus_relase_msg_data(nano_bus_msg_t *msg)
{
if (msg->data && !msg->no_free) {
json_delete(msg->data);
}
msg->data = NULL;
msg->no_free = FALSE;
}
static void nano_bus_relase_msg(nano_bus_msg_t *msg)
{
if (!msg) {
return;
}
if (msg->obj) {
osal_free(msg->obj);
}
if (msg->method) {
osal_free(msg->method);
}
nano_bus_relase_msg_data(msg);
osal_free(msg);
}
static SH_INT32 _nano_bus_send_reply(nano_switch_fd_t fd, SH_UINT8 addr, nano_bus_msg_t *msg, json_t *data, SH_INT32 status)
{
nano_switch_fd_addr_t fd_addr;
nano_bus_relase_msg_data(msg);
msg->data = data;
msg->type = NANO_BUS_MSG_RESPONSE;
msg->status = status;
fd_addr.local_addr = addr;
if (nano_switch_send(fd, &fd_addr, (SH_CHAR*)msg, sizeof(*msg)) != 0) {
nano_bus_relase_msg(msg);
return -1;
}
return 0;
}
static void nano_busd_add_obj_cb(nano_bus_msg_t *msg, void *context)
{
nano_busd_context_t *ctx = (nano_busd_context_t*)context;
nano_bus_object_t *obj;
json_t *jname;
SH_INT32 status = -1;
if (!msg || !msg->data) {
goto out;
}
jname = json_get_object_item(msg->data, "name");
if (!jname) {
goto out;
}
list_for_each_entry(obj, &ctx->objs, list) {
if (!OSAL_STRCMP(obj->name, jname->valuestring)) {
goto out;
}
}
obj = osal_malloc(sizeof(nano_bus_object_t));
if (!obj) {
goto out;
}
OSAL_MEMZERO(obj, sizeof(nano_bus_object_t));
obj->name = osal_strdup(jname->valuestring);
if (!obj->name) {
osal_free(obj);
goto out;
}
obj->addr = msg->src_addr;
list_add(&obj->list, &ctx->objs);
status = 0;
out:
if (msg) {
_nano_bus_send_reply(ctx->sock.fd, msg->src_addr, msg, NULL, status);
}
}
static void nano_busd_register_event_cb(nano_bus_msg_t *msg, void *context)
{
nano_busd_context_t *ctx = (nano_busd_context_t*)context;
nano_busd_event_t *pevt, *pnevt = NULL;
nano_busd_event_node_t *pevt_node, *pnevt_node;
json_t *jevt;
SH_INT32 i, num, status = -1;
SH_BOOL found;
if (!msg || !msg->data) {
goto out;
}
list_for_each_entry(pevt, &ctx->evts, list) {
if (pevt->addr == msg->src_addr) {
pnevt = pevt;
break;
}
}
if (!pnevt) {
pnevt = osal_malloc(sizeof(nano_busd_event_t));
if (!pnevt) {
goto out;
}
OSAL_MEMZERO(pnevt, sizeof(nano_busd_event_t));
INIT_LIST_HEAD(&pnevt->evts);
pnevt->addr = msg->src_addr;
list_add(&pnevt->list, &ctx->evts);
}
num = json_get_array_size(msg->data);
for (i = 0; i < num; i++) {
jevt = json_get_array_item(msg->data, i);
found = FALSE;
list_for_each_entry(pevt_node, &pnevt->evts, list) {
if (!OSAL_STRCMP(pevt_node->name, jevt->valuestring)) {
pevt_node->ref_count++;
found = TRUE;
break;
}
}
if (!found) {
pnevt_node = osal_malloc(sizeof(nano_busd_event_node_t));
if (pnevt_node) {
OSAL_MEMZERO(pnevt_node, sizeof(nano_busd_event_node_t));
pnevt_node->name = osal_strdup(jevt->valuestring);
pnevt_node->ref_count = 1;
list_add(&pnevt_node->list, &pnevt->evts);
}
}
}
status = 0;
out:
if (msg) {
_nano_bus_send_reply(ctx->sock.fd, msg->src_addr, msg, NULL, status);
}
}
static void nano_busd_run_callback_cb(nano_bus_msg_t *msg, void *context)
{
nano_busd_context_t *ctx = (nano_busd_context_t*)context;
SH_INT32 status = -1;
if (!msg || !msg->cb) {
goto out;
}
msg->cb(msg->cb_priv);
status = 0;
out:
if (msg) {
_nano_bus_send_reply(ctx->sock.fd, msg->src_addr, msg, NULL, status);
}
}
#ifdef SHIP_LIB_NANO_BUS_DELETE_API
static void nano_busd_delete_obj_cb(nano_bus_msg_t *msg, void *context)
{
nano_busd_context_t *ctx = (nano_busd_context_t*)context;
nano_bus_object_t *obj;
json_t *jname;
SH_INT32 status = -1;
if (!msg || !msg->data) {
goto out;
}
jname = json_get_object_item(msg->data, "name");
if (!jname) {
goto out;
}
status = 0;
list_for_each_entry(obj, &ctx->objs, list) {
if (!OSAL_STRCMP(obj->name, jname->valuestring)) {
if (obj->addr == msg->src_addr) {
list_del(&obj->list);
osal_free(obj->name);
osal_free(obj);
} else {
status = -1;
}
break;
}
}
out:
if (msg) {
_nano_bus_send_reply(ctx->sock.fd, msg->src_addr, msg, NULL, status);
}
}
static void nano_busd_unregister_event_cb(nano_bus_msg_t *msg, void *context)
{
nano_busd_context_t *ctx = (nano_busd_context_t*)context;
nano_busd_event_t *pevt, *pnevt = NULL;
nano_busd_event_node_t *pevt_node;
json_t *jevt;
SH_INT32 i, num, status = -1;
if (!msg || !msg->data) {
goto out;
}
list_for_each_entry(pevt, &ctx->evts, list) {
if (pevt->addr == msg->src_addr) {
pnevt = pevt;
break;
}
}
if (!pnevt) {
status = 0;
goto out;
}
num = json_get_array_size(msg->data);
for (i = 0; i < num; i++) {
jevt = json_get_array_item(msg->data, i);
list_for_each_entry(pevt_node, &pnevt->evts, list) {
if (!OSAL_STRCMP(pevt_node->name, jevt->valuestring)) {
pevt_node->ref_count--;
if (pevt_node->ref_count == 0) {
list_del(&pevt_node->list);
osal_free(pevt_node->name);
osal_free(pevt_node);
}
break;
}
}
}
status = 0;
out:
if (msg) {
_nano_bus_send_reply(ctx->sock.fd, msg->src_addr, msg, NULL, status);
}
}
#endif
#ifdef SHIP_LIB_NANO_BUS_CLI_API
static void nano_busd_list_cb(nano_bus_msg_t *msg, void *context)
{
nano_busd_context_t *ctx = (nano_busd_context_t*)context;
nano_bus_object_t *obj;
json_t *jdata = NULL;
SH_INT32 status = -1;
if (!msg) {
goto out;
}
jdata = json_create_array();
if (!jdata) {
goto out;
}
list_for_each_entry(obj, &ctx->objs, list) {
json_add_item_toarray(jdata, json_create_string(obj->name));
}
status = 0;
out:
if (msg) {
_nano_bus_send_reply(ctx->sock.fd, msg->src_addr, msg, jdata, status);
}
}
#endif
static const nano_bus_method_t nano_busd_methods[] = {
{.name = "add_obj", .cb = nano_busd_add_obj_cb},
{.name = "register_event", .cb = nano_busd_register_event_cb},
{.name = "run_callback", .cb = nano_busd_run_callback_cb},
#ifdef SHIP_LIB_NANO_BUS_DELETE_API
{.name = "delete_obj", .cb = nano_busd_delete_obj_cb},
{.name = "unregister_event", .cb = nano_busd_unregister_event_cb},
#endif
#ifdef SHIP_LIB_NANO_BUS_CLI_API
{.name = "list", .cb = nano_busd_list_cb},
#endif
};
static nano_bus_object_t nano_busd_obj = {
.name = "nano_bus",
.methods = nano_busd_methods,
.n_methods = ARRAY_SIZE(nano_busd_methods),
};
static void nano_busd_process_request(nano_busd_context_t *ctx, nano_bus_msg_t *msg)
{
nano_bus_object_t *obj;
SH_INT32 i;
SH_BOOL processed = 0;
nano_switch_fd_addr_t addr;
list_for_each_entry(obj, &ctx->objs, list) {
if (OSAL_STRCMP(obj->name, msg->obj)) {
continue;
}
if (obj->n_methods > 0) {
/* process locally */
for (i = 0; i < obj->n_methods; i++) {
if (OSAL_STRCMP(obj->methods[i].name, msg->method)) {
continue;
}
processed = 1;
if (obj->methods[i].cb) {
obj->methods[i].cb(msg, (void*)ctx);
} else {
nano_bus_relase_msg(msg);
}
break;
}
} else {
processed = 1;
/* forward to client */
msg->dst_addr = obj->addr;
addr.local_addr = obj->addr;
if (nano_switch_send(ctx->sock.fd, &addr, (SH_CHAR*)msg, sizeof(*msg)) != 0) {
nano_bus_relase_msg(msg);
}
}
break;
}
if (!processed) {
SHIP_D_PRINTF("obj %s, method %s not found\n", msg->obj ? msg->obj : "NULL", msg->method ? msg->method : "NULL");
/* send an error reply */
_nano_bus_send_reply(ctx->sock.fd, msg->src_addr, msg, NULL, OSAL_ERROR);
}
}
static void nano_busd_process_response(nano_busd_context_t *ctx, nano_bus_msg_t *msg)
{
nano_switch_fd_addr_t addr;
addr.local_addr = msg->dst_addr;
/* forward to client */
if (nano_switch_send(ctx->sock.fd, &addr, (SH_CHAR*)msg, sizeof(*msg)) != 0)
nano_bus_relase_msg(msg);
}
static void nano_busd_process_event(nano_busd_context_t *ctx, nano_bus_msg_t *msg)
{
nano_busd_event_t *evt;
nano_busd_event_node_t *evt_node;
nano_bus_msg_t *msg2;
nano_switch_fd_addr_t addr;
if (msg->evt) {
list_for_each_entry(evt, &ctx->evts, list) {
list_for_each_entry(evt_node, &evt->evts, list) {
if (!OSAL_STRCMP(evt_node->name, msg->evt)) {
msg2 = osal_malloc(sizeof(*msg2));
if (msg2) {
OSAL_MEMZERO(msg2, sizeof(*msg2));
msg2->type = msg->type;
msg2->evt = osal_strdup(msg->evt);
msg2->data = json_duplicate(msg->data, 1);
addr.local_addr = evt->addr;
if (nano_switch_send(ctx->sock.fd, &addr, (SH_CHAR*)msg2, sizeof(*msg2)) != 0)
nano_bus_relase_msg(msg2);
}
break;
}
}
}
}
nano_bus_relase_msg(msg);
}
static void nano_busd_process_msg(nano_busd_context_t *ctx, nano_bus_msg_t *msg)
{
if (!msg)
return;
switch (msg->type) {
case NANO_BUS_MSG_REQUEST:
NANO_BUS_LOG("request id=%d, src=%d, dst=%d, obj=%s, method=%s, data=%p\n", msg->id, msg->src_addr,
msg->dst_addr, msg->obj, msg->method, msg->data);
nano_busd_process_request(ctx, msg);
break;
case NANO_BUS_MSG_RESPONSE:
NANO_BUS_LOG("response id=%d, src=%d, dst=%d, obj=%s, method=%s, status=%d, data=%p\n", msg->id, msg->src_addr,
msg->dst_addr, msg->obj, msg->method, msg->status, msg->data);
nano_busd_process_response(ctx, msg);
break;
case NANO_BUS_MSG_EVENT:
NANO_BUS_LOG("event id=%d, src=%d, dst=%d, event=%s, data=%p\n", msg->id, msg->src_addr,
msg->dst_addr, msg->evt, msg->data);
nano_busd_process_event(ctx, msg);
break;
default:
SHIP_D_PRINTF("nano_busd:unknown msg type %d\n", msg->type);
nano_bus_relase_msg(msg);
}
}
static void nano_busd_fd_handler(struct nano_loop_fd *u, SH_UINT32 events)
{
nano_busd_context_t *ctx = container_of(u, nano_busd_context_t, sock);
nano_bus_msg_t *msg = NULL;
nano_switch_fd_addr_t remote_addr;
if (nano_switch_receive(ctx->sock.fd, &remote_addr, (SH_CHAR **)&msg, NULL) == 0) {
if (msg)
msg->src_addr = remote_addr.local_addr;
nano_busd_process_msg(ctx, msg);
}
}
static SH_BOOL daemon_started = FALSE;
static struct nano_loop_context *main_loop_ctx;
static nano_bus_context_t *main_bus_ctx;
static nano_busd_context_t *busd_ctx;
static void nano_busd_entry(void *arg)
{
nano_switch_fd_addr_t addr;
busd_ctx = osal_malloc(sizeof(nano_busd_context_t));
if (!busd_ctx) {
SHIP_W_PRINTF("ctx null\n");
goto out;
}
OSAL_MEMSET(busd_ctx, 0, sizeof(nano_busd_context_t));
main_loop_ctx = nano_loop_new();
if (!main_loop_ctx) {
SHIP_W_PRINTF("loop null\n");
goto out;
}
busd_ctx->loop_ctx = main_loop_ctx;
busd_ctx->sock.cb = nano_busd_fd_handler;
OSAL_MEMZERO(&addr, sizeof(nano_switch_fd_addr_t));
addr.local_addr = NANO_BUS_DAEMON_ADDR;
busd_ctx->sock.fd = nano_switch_endpoint_open(NANO_SWITCH_EP_TYPE_LOCAL, &addr, NULL);
if (!busd_ctx->sock.fd) {
SHIP_W_PRINTF("fd fail\n");
goto out;
}
INIT_LIST_HEAD(&busd_ctx->objs);
INIT_LIST_HEAD(&busd_ctx->evts);
list_add(&nano_busd_obj.list, &busd_ctx->objs);
nano_loop_fd_add(main_loop_ctx, &busd_ctx->sock);
main_bus_ctx = nano_bus_context_create();
nano_bus_add_loop(main_loop_ctx, main_bus_ctx);
daemon_started = TRUE;
nano_loop_run(main_loop_ctx);
out:
nano_loop_done(main_loop_ctx);
if (busd_ctx)
osal_free(busd_ctx);
return;
}
nano_bus_context_t* nano_bus_main_ctx_get()
{
return main_bus_ctx;
}
struct nano_loop_context* nano_bus_main_loop_get()
{
return main_loop_ctx;
}
SH_INT32 nano_bus_init()
{
osal_thread_t id;
osal_thread_create(&id, "ml", nano_busd_entry, (SH_ULONG)NULL, CONFIG_LIB_MAIN_LOOP_STACK_SIZE, OSAL_THREAD_PRIORITY_HIGH, 0);
while (1) {
if (!daemon_started)
osal_sleep_ms(2);
else
break;
}
return OSAL_OK;
}
static void nano_bus_process_request(nano_bus_context_t *ctx, nano_bus_msg_t *msg)
{
nano_bus_object_t *obj;
SH_INT32 i;
SH_BOOL processed = FALSE;
list_for_each_entry(obj, &ctx->objs, list) {
if (OSAL_STRCMP(obj->name, msg->obj)) {
continue;
}
for (i = 0; i < obj->n_methods; i++) {
/*
globbing should be the last in registered methods, otherwise the method after it will never be called
*/
if (OSAL_STRCMP(obj->methods[i].name, msg->method) && OSAL_STRCMP(obj->methods[i].name, "*")) {
continue;
}
processed = TRUE;
if (obj->methods[i].cb) {
obj->methods[i].cb(msg, (void*)ctx);
} else {
nano_bus_relase_msg(msg);
}
break;
}
break;
}
if (!processed) {
SHIP_D_PRINTF("obj %s, method %s not found\n", msg->obj ? msg->obj : "NULL", msg->method ? msg->method : "NULL");
/* send an error reply */
nano_bus_send_reply(ctx, msg, NULL, OSAL_ERROR);
}
}
static void nano_bus_process_response(nano_bus_context_t *ctx, nano_bus_msg_t *msg)
{
SH_BOOL found = FALSE;
nano_bus_request_t *req, *n;
list_for_each_entry_safe(req, n, &ctx->reqs, list) {
if (req->id == msg->id) {
found = TRUE;
req->done = TRUE;
list_del(&req->list);
if (req->cb)
{
req->cb(msg->status, msg->data, req->priv);
}
nano_bus_relase_msg(msg);
if (req->async)
osal_free(req);
break;
}
}
if (!found)
nano_bus_relase_msg(msg);
}
static void nano_bus_process_event(nano_bus_context_t *ctx, nano_bus_msg_t *msg)
{
nano_bus_event_t *evt;
if (msg->evt) {
list_for_each_entry(evt, &ctx->evts, list) {
/* find all matching event, there may be multipe call back with the same name */
if (!OSAL_STRCMP(evt->name, msg->evt)) {
if (evt->cb)
evt->cb(msg, (void*)ctx);
}
}
}
nano_bus_relase_msg(msg);
}
static void nano_bus_process_msg(nano_bus_context_t *ctx, nano_bus_msg_t *msg)
{
if (!msg)
return;
switch (msg->type) {
case NANO_BUS_MSG_REQUEST:
NANO_BUS_LOG("request id=%d, src=%d, dst=%d, obj=%s, method=%s, data=%p\r\n", msg->id, msg->src_addr,
msg->dst_addr, msg->obj, msg->method, msg->data);
nano_bus_process_request(ctx, msg);
break;
case NANO_BUS_MSG_RESPONSE:
NANO_BUS_LOG("response id=%d, src=%d, dst=%d, obj=%s, method=%s, status=%d, data=%p\r\n", msg->id, msg->src_addr,
msg->dst_addr, msg->obj, msg->method, msg->status, msg->data);
nano_bus_process_response(ctx, msg);
break;
case NANO_BUS_MSG_EVENT:
NANO_BUS_LOG("event id=%d, src=%d, dst=%d, event=%s, data=%p\n", msg->id, msg->src_addr,
msg->dst_addr, msg->evt, msg->data);
nano_bus_process_event(ctx, msg);
break;
default:
SHIP_D_PRINTF("nano_bus:unknown msg type %d\n", msg->type);
nano_bus_relase_msg(msg);
}
}
/* do not release data when error happen */
static SH_INT32 nano_bus_start_request(nano_bus_context_t *ctx, nano_bus_request_t *req, SH_CHAR *obj,
SH_CHAR *method, json_t *data, nano_bus_main_loop_cb_t cb, void *cb_priv, SH_BOOL nofree)
{
nano_bus_msg_t *msg;
SH_INT32 ret = -1;
nano_switch_fd_addr_t addr;
msg = osal_malloc(sizeof(nano_bus_msg_t));
if (!msg) {
goto out;
}
OSAL_MEMZERO(msg, sizeof(nano_bus_msg_t));
msg->type = NANO_BUS_MSG_REQUEST;
msg->obj = osal_strdup(obj);
msg->method = osal_strdup(method);
if (!msg->obj || !msg->method) {
nano_bus_relase_msg(msg);
goto out;
}
msg->data = data;
msg->cb = cb;
msg->cb_priv = cb_priv;
msg->no_free = nofree;
msg->id = ctx->msgid++;
if (msg->id < 0) {
/* msgid seems overflow, start from 0 again */
msg->id = 0;
ctx->msgid = 1;
}
req->id = msg->id;
addr.local_addr = NANO_BUS_DAEMON_ADDR;
if (nano_switch_send(ctx->sock.fd, &addr, (SH_CHAR*)msg, sizeof(*msg)) != 0) {
msg->data = NULL;
nano_bus_relase_msg(msg);
goto out;
}
list_add(&req->list, &ctx->reqs);
ret = 0;
out:
return ret;
}
static SH_INT32 nano_bus_complete_request(nano_bus_context_t *ctx, nano_bus_request_t *req, SH_INT32 tmo)
{
nano_bus_msg_t *msg;
SH_UINT64 time_end = 0, timeout, tv;
nano_switch_fd_t fds[2];
SH_INT32 len, ret, i;
nano_switch_fd_addr_t remote_addr;
if (tmo >= 0) {
time_end = osal_time_ms() + tmo;
}
while (!req->done) {
tv = osal_time_ms();
if (tmo >= 0) {
if (time_end <= tv) {
break;
} else {
timeout = time_end - tv;
}
} else {
timeout = -1;
}
if (ctx->loop_ctx == main_loop_ctx) {
/* if in mainloop we must also process the messages on busd sock */
len = 2;
fds[0] = busd_ctx->sock.fd;
fds[1] = ctx->sock.fd;
} else {
len = 1;
fds[0] = ctx->sock.fd;
}
ret = nano_switch_select(fds, &len, timeout);
if (ret != 0 || len < 1) {
continue;
}
for (i = 0; i < len; i++) {
msg = NULL;
ret = nano_switch_receive(fds[i], &remote_addr, (SH_CHAR **)&msg, NULL);
if (ret != 0) {
continue;
}
if (fds[i] == ctx->sock.fd) {
nano_bus_process_msg(ctx, msg);
} else if (fds[i] == busd_ctx->sock.fd) {
msg->src_addr = remote_addr.local_addr;
nano_busd_process_msg(busd_ctx, msg);
} else {
nano_bus_relase_msg(msg);
}
}
}
if (!req->done) {
list_del(&req->list);
if (req->cb)
req->cb(OSAL_ERR_TIMEOUT, NULL, req->priv);
}
return 0;
}
static SH_INT32 nano_bus_next_req_timeout(nano_bus_context_t *ctx)
{
nano_bus_request_t *req;
SH_UINT64 tv, now = osal_time_ms();
if (list_empty(&ctx->reqs)) {
return -1;
} else {
req = list_first_entry(&ctx->reqs, nano_bus_request_t, list);
tv = req->time;
}
list_for_each_entry(req, &ctx->reqs, list) {
if (tv > req->time)
tv = req->time;
}
if (tv > now)
return tv - now;
else
return 0;
}
static void nano_bus_fd_handler(struct nano_loop_fd *u, SH_UINT32 events)
{
nano_bus_context_t *ctx = container_of(u, nano_bus_context_t, sock);
nano_bus_msg_t *msg;
if (nano_switch_receive(ctx->sock.fd, NULL, (SH_CHAR **)&msg, NULL) == 0) {
nano_bus_process_msg(ctx, msg);
}
}
static void nano_bus_timer_handler(struct nano_loop_timeout *t)
{
nano_bus_context_t *ctx = container_of(t, nano_bus_context_t, timer);
nano_bus_request_t *req, *n;
SH_UINT64 now = osal_time_ms();
list_for_each_entry_safe(req, n, &ctx->reqs, list) {
if (req->time <= now) {
if (req->cb)
req->cb(OSAL_ERR_TIMEOUT, NULL, req->priv);
list_del(&req->list);
osal_free(req);
}
}
}
nano_bus_context_t* nano_bus_context_create()
{
nano_bus_context_t *ctx;
nano_switch_fd_addr_t addr;
ctx = osal_malloc(sizeof(nano_bus_context_t));
if (ctx) {
OSAL_MEMZERO(ctx, sizeof(nano_bus_context_t));
INIT_LIST_HEAD(&ctx->objs);
INIT_LIST_HEAD(&ctx->reqs);
INIT_LIST_HEAD(&ctx->evts);
ctx->timer.cb = nano_bus_timer_handler;
OSAL_MEMZERO(&addr, sizeof(nano_switch_fd_addr_t));
addr.local_addr = 0;
ctx->sock.fd = nano_switch_endpoint_open(NANO_SWITCH_EP_TYPE_LOCAL, &addr, NULL);
ctx->sock.cb = nano_bus_fd_handler;
if (!ctx->sock.fd) {
osal_free(ctx);
return NULL;
}
}
return ctx;
}
#ifdef SHIP_LIB_NANO_BUS_DELETE_API
void nano_bus_context_destroy(nano_bus_context_t *ctx)
{
nano_bus_object_t *obj, *nobj;
nano_bus_event_t *evt, *nevt;
nano_bus_request_t *req, *nreq;
list_for_each_entry_safe(obj, nobj, &ctx->objs, list) {
nano_bus_delete_obj(ctx, obj->name);
list_del(&obj->list);
}
list_for_each_entry_safe(evt, nevt, &ctx->evts, list) {
nano_bus_unregister_events(ctx, evt, 1);
list_del(&evt->list);
}
list_for_each_entry_safe(req, nreq, &ctx->reqs, list) {
req->done = TRUE;
list_del(&req->list);
if (req->cb)
req->cb(OSAL_ERR_CANCEL, NULL, req->priv);
if (req->async)
osal_free(req);
}
nano_loop_fd_delete(&ctx->sock);
nano_switch_endpoint_close(ctx->sock.fd);
nano_loop_timeout_cancel(&ctx->timer);
osal_free(ctx);
}
#endif
void nano_bus_add_loop(struct nano_loop_context *loop_ctx, nano_bus_context_t *ctx)
{
if (!loop_ctx || !ctx)
return;
ctx->loop_ctx = loop_ctx;
nano_loop_fd_add(loop_ctx, &ctx->sock);
}
static void nano_bus_call_common_cb(SH_INT32 status, json_t *resp, void *priv)
{
SH_INT32 ret = -1;
if (status == OSAL_OK)
ret = 0;
if (priv)
*(SH_INT32*)priv = ret;
}
SH_INT32 nano_bus_add_obj(nano_bus_context_t *ctx, nano_bus_object_t *obj)
{
nano_bus_request_t req;
json_t *data;
SH_INT32 ret = -1, status = -1;
data = json_create_object();
if (!data)
goto out;
json_add_string_toObject(data, "name", obj->name);
OSAL_MEMZERO(&req, sizeof(req));
req.cb = nano_bus_call_common_cb;
req.priv = &status;
if (nano_bus_start_request(ctx, &req, "nano_bus", "add_obj", data, NULL, NULL, FALSE) != 0)
goto out;
data = NULL;
nano_bus_complete_request(ctx, &req, 20000);
if (status == 0) {
ret = 0;
list_add(&obj->list, &ctx->objs);
}
out:
if (data)
json_delete(data);
return ret;
}
#ifdef SHIP_LIB_NANO_BUS_DELETE_API
SH_INT32 nano_bus_delete_obj(nano_bus_context_t *ctx, SH_CHAR *name)
{
nano_bus_request_t req;
json_t *data;
SH_INT32 ret = -1, status = -1;
data = json_create_object();
if (!data)
goto out;
json_add_string_toObject(data, "name", name);
OSAL_MEMZERO(&req, sizeof(req));
req.cb = nano_bus_call_common_cb;
req.priv = &status;
if (nano_bus_start_request(ctx, &req, "nano_bus", "delete_obj", data, NULL, NULL, FALSE) != 0)
goto out;
data = NULL;
nano_bus_complete_request(ctx, &req, 20000);
if (status == 0) {
ret = 0;
}
out:
if (data)
json_delete(data);
return ret;
}
#endif
SH_INT32 nano_bus_invoke(nano_bus_context_t *ctx, SH_CHAR *obj, SH_CHAR *method, json_t *data, SH_BOOL no_free,
nano_bus_request_cb_t cb, void *priv, SH_INT32 tmo, SH_BOOL sync)
{
nano_bus_request_t *req;
SH_INT32 ret = OSAL_ERROR;
req = osal_malloc(sizeof(nano_bus_request_t));
if (!req)
goto out;
OSAL_MEMZERO(req, sizeof(nano_bus_request_t));
req->cb = cb;
req->priv = priv;
if (nano_bus_start_request(ctx, req, obj, method, data, NULL, NULL, no_free) < 0)
goto out;
if (sync) {
nano_bus_complete_request(ctx, req, tmo);
osal_free(req);
ret = 0;
} else {
req->time = osal_time_ms() + tmo;
req->async = TRUE;
nano_loop_timeout_set(ctx->loop_ctx, &ctx->timer, nano_bus_next_req_timeout(ctx));
ret = req->id;
}
out:
return ret;
}
SH_INT32 nano_bus_send_reply(nano_bus_context_t *ctx, nano_bus_msg_t *msg, json_t *data, SH_INT32 status)
{
SH_UINT8 tmp;
tmp = msg->src_addr;
msg->src_addr = msg->dst_addr;
msg->dst_addr = tmp;
return _nano_bus_send_reply(ctx->sock.fd, NANO_BUS_DAEMON_ADDR, msg, data, status);
}
void nano_bus_cancel_request(nano_bus_context_t *ctx, SH_INT32 request_id)
{
nano_bus_request_t *req, *n;
list_for_each_entry_safe(req, n, &ctx->reqs, list) {
if (req->id == request_id) {
req->done = TRUE;
list_del(&req->list);
if (req->cb)
req->cb(OSAL_ERR_CANCEL, NULL, req->priv);
if (req->async)
osal_free(req);
break;
}
}
}
SH_INT32 nano_bus_run_cb_in_main_loop(nano_bus_context_t *ctx, nano_bus_main_loop_cb_t cb, void *priv)
{
nano_bus_request_t req;
SH_INT32 ret = -1, status = -1;
OSAL_MEMZERO(&req, sizeof(req));
req.cb = nano_bus_call_common_cb;
req.priv = &status;
if (nano_bus_start_request(ctx, &req, "nano_bus", "run_callback", NULL, cb, priv, FALSE) != 0) {
goto out;
}
nano_bus_complete_request(ctx, &req, 20000);
if (status == 0) {
ret = 0;
}
out:
return ret;
}
SH_INT32 nano_bus_register_events(nano_bus_context_t *ctx, nano_bus_event_t *evts, SH_INT32 n_evts)
{
nano_bus_request_t req;
json_t *data, *item;
SH_INT32 ret = -1, status = -1, i;
data = json_create_array();
if (!data)
goto out;
for (i = 0; i < n_evts; i++) {
item = json_create_string(evts[i].name);
if (!item)
continue;
json_add_item_toarray(data, item);
}
OSAL_MEMZERO(&req, sizeof(req));
req.cb = nano_bus_call_common_cb;
req.priv = &status;
if (nano_bus_start_request(ctx, &req, "nano_bus", "register_event", data, NULL, NULL, FALSE) != 0)
goto out;
data = NULL;
nano_bus_complete_request(ctx, &req, 20000);
if (status == 0) {
ret = 0;
for (i = 0; i < n_evts; i++) {
list_add(&evts[i].list, &ctx->evts);
}
}
out:
if (data)
json_delete(data);
return ret;
}
#ifdef SHIP_LIB_NANO_BUS_DELETE_API
SH_INT32 nano_bus_unregister_events(nano_bus_context_t *ctx, nano_bus_event_t *evts, SH_INT32 n_evts)
{
nano_bus_request_t req;
json_t *data, *item;
SH_INT32 ret = -1, status = -1, i;
data = json_create_array();
if (!data)
goto out;
for (i = 0; i < n_evts; i++) {
item = json_create_string(evts[i].name);
if (!item)
continue;
json_add_item_toarray(data, item);
}
OSAL_MEMZERO(&req, sizeof(req));
req.cb = nano_bus_call_common_cb;
req.priv = &status;
if (nano_bus_start_request(ctx, &req, "nano_bus", "unregister_event", data, NULL, NULL, FALSE) != 0)
goto out;
data = NULL;
nano_bus_complete_request(ctx, &req, 20000);
if (status == 0) {
ret = 0;
}
out:
if (data)
json_delete(data);
return ret;
}
#endif
SH_INT32 nano_bus_send_event(nano_bus_context_t *ctx, SH_CHAR *evt, json_t *data)
{
nano_bus_msg_t *msg;
SH_INT32 ret = -1;
nano_switch_fd_addr_t addr;
msg = osal_malloc(sizeof(*msg));
if (!msg)
goto out;
memset(msg, 0, sizeof(*msg));
msg->type = NANO_BUS_MSG_EVENT;
msg->evt = osal_strdup(evt);
msg->data = data;
addr.local_addr = NANO_BUS_DAEMON_ADDR;
if (nano_switch_send(ctx->sock.fd, &addr, (SH_CHAR*)msg, sizeof(*msg)) != 0) {
nano_bus_relase_msg(msg);
return -1;
}
ret = 0;
out:
return ret;
}
分析一下这个
最新发布