newtmgr_oic; run OIC server, and newtmgr protocol over it.
Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/commit/63dfa915 Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/63dfa915 Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/63dfa915 Branch: refs/heads/sterly_refactor Commit: 63dfa915288fc48f9ae265b31979900fafb49d6a Parents: 3ba8d18 Author: Marko Kiiskila <ma...@runtime.io> Authored: Tue Sep 20 17:54:12 2016 -0700 Committer: Marko Kiiskila <ma...@runtime.io> Committed: Tue Sep 20 17:54:12 2016 -0700 ---------------------------------------------------------------------- libs/newtmgr_oic/include/newtmgr/newtmgr.h | 112 +++++ libs/newtmgr_oic/include/newtmgr/newtmgr_priv.h | 24 + libs/newtmgr_oic/pkg.yml | 44 ++ libs/newtmgr_oic/src/newtmgr.c | 504 +++++++++++++++++++ 4 files changed, 684 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/63dfa915/libs/newtmgr_oic/include/newtmgr/newtmgr.h ---------------------------------------------------------------------- diff --git a/libs/newtmgr_oic/include/newtmgr/newtmgr.h b/libs/newtmgr_oic/include/newtmgr/newtmgr.h new file mode 100644 index 0000000..dec4a5a --- /dev/null +++ b/libs/newtmgr_oic/include/newtmgr/newtmgr.h @@ -0,0 +1,112 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _NEWTMGR_H_ +#define _NEWTMGR_H_ + +#include <json/json.h> +#include <inttypes.h> +#include <os/os.h> + +/* MTU for newtmgr responses */ +#define NMGR_MAX_MTU 1024 + +#ifndef STR +/* Stringification of constants */ +#define STR(x) #x +#endif + +/* First 64 groups are reserved for system level newtmgr commands. + * Per-user commands are then defined after group 64. + */ +#define NMGR_GROUP_ID_DEFAULT (0) +#define NMGR_GROUP_ID_IMAGE (1) +#define NMGR_GROUP_ID_STATS (2) +#define NMGR_GROUP_ID_CONFIG (3) +#define NMGR_GROUP_ID_LOGS (4) +#define NMGR_GROUP_ID_CRASH (5) +#define NMGR_GROUP_ID_SPLIT (6) +#define NMGR_GROUP_ID_PERUSER (64) + +#define NMGR_OP_READ (0) +#define NMGR_OP_READ_RSP (1) +#define NMGR_OP_WRITE (2) +#define NMGR_OP_WRITE_RSP (3) + + +/** + * Newtmgr JSON error codes + */ +#define NMGR_ERR_EOK (0) +#define NMGR_ERR_EUNKNOWN (1) +#define NMGR_ERR_ENOMEM (2) +#define NMGR_ERR_EINVAL (3) +#define NMGR_ERR_ETIMEOUT (4) +#define NMGR_ERR_ENOENT (5) +#define NMGR_ERR_EPERUSER (256) + +struct nmgr_hdr { + uint8_t nh_op; /* NMGR_OP_XXX */ + uint8_t nh_flags; + uint16_t nh_len; /* length of the payload */ + uint16_t nh_group; /* NMGR_GROUP_XXX */ + uint8_t nh_seq; /* sequence number */ + uint8_t nh_id; /* message ID within group */ +}; + +struct nmgr_jbuf { + /* json_buffer must be first element in the structure */ + struct json_buffer njb_buf; + struct json_encoder njb_enc; + char *njb_in; + uint16_t njb_in_off; + uint16_t njb_in_end; + char *njb_out; + uint16_t njb_out_off; + uint16_t njb_out_end; +}; +int nmgr_jbuf_setoerr(struct nmgr_jbuf *njb, int errcode); + +typedef int (*nmgr_handler_func_t)(struct nmgr_jbuf *); + +#define NMGR_HANDLER_FUNC(__name) \ + int __name(struct nmgr_hdr *nmr, struct os_mbuf *req, uint16_t srcoff, \ + struct os_mbuf *rsp) + +struct nmgr_handler { + nmgr_handler_func_t nh_read; + nmgr_handler_func_t nh_write; +}; + +struct nmgr_group { + struct nmgr_handler *ng_handlers; + uint16_t ng_handlers_count; + uint16_t ng_group_id; + STAILQ_ENTRY(nmgr_group) ng_next; +}; + +#define NMGR_GROUP_SET_HANDLERS(__group, __handlers) \ + (__group)->ng_handlers = (__handlers); \ + (__group)->ng_handlers_count = (sizeof((__handlers)) / \ + sizeof(struct nmgr_handler)); + +int nmgr_oic_init(uint8_t, os_stack_t *, uint16_t); +int nmgr_group_register(struct nmgr_group *group); + +#endif /* _NETMGR_H */ http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/63dfa915/libs/newtmgr_oic/include/newtmgr/newtmgr_priv.h ---------------------------------------------------------------------- diff --git a/libs/newtmgr_oic/include/newtmgr/newtmgr_priv.h b/libs/newtmgr_oic/include/newtmgr/newtmgr_priv.h new file mode 100644 index 0000000..7217711 --- /dev/null +++ b/libs/newtmgr_oic/include/newtmgr/newtmgr_priv.h @@ -0,0 +1,24 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +#ifndef __NETMGR_PRIV_H_ +#define __NETMGR_PRIV_H_ + +extern struct os_eventq g_nmgr_evq; + +#endif http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/63dfa915/libs/newtmgr_oic/pkg.yml ---------------------------------------------------------------------- diff --git a/libs/newtmgr_oic/pkg.yml b/libs/newtmgr_oic/pkg.yml new file mode 100644 index 0000000..75d20f5 --- /dev/null +++ b/libs/newtmgr_oic/pkg.yml @@ -0,0 +1,44 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: libs/newtmgr_oic +pkg.description: Server-side newtmgr functionality for OIC +pkg.author: "Apache Mynewt <d...@mynewt.incubator.apache.org>" +pkg.homepage: "http://mynewt.apache.org/" +pkg.keywords: + +pkg.deps: + - libs/os + - libs/iotivity + - libs/json + - libs/newtmgr/nmgr_os + - libs/util + - libs/testutil + - libs/shell + - sys/reboot + +pkg.cflags: + - -DOC_SERVER + +pkg.apis: + - newtmgr + +pkg.features: + - NEWTMGR + - OC_SERVER http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/63dfa915/libs/newtmgr_oic/src/newtmgr.c ---------------------------------------------------------------------- diff --git a/libs/newtmgr_oic/src/newtmgr.c b/libs/newtmgr_oic/src/newtmgr.c new file mode 100644 index 0000000..434bf46 --- /dev/null +++ b/libs/newtmgr_oic/src/newtmgr.c @@ -0,0 +1,504 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include <os/os.h> +#include <os/endian.h> + +#include <assert.h> +#include <string.h> + +#include <newtmgr/newtmgr.h> +#include <nmgr_os/nmgr_os.h> + +#include <iotivity/oc_api.h> + +#include "newtmgr/newtmgr_priv.h" + +#define NMGR_OC_EVENT (OS_EVENT_T_PERUSER) +#define NMGR_OC_TIMER (OS_EVENT_T_PERUSER + 1) + +struct nmgr_state { + struct os_mutex ns_group_lock; + STAILQ_HEAD(, nmgr_group) ns_groups; + struct os_event ns_oc_event; + struct os_callout ns_oc_timer; + struct os_task ns_task; + struct nmgr_jbuf ns_jbuf; + char ns_rsp[NMGR_MAX_MTU]; +}; + +static struct nmgr_state nmgr_state = { + .ns_groups = STAILQ_HEAD_INITIALIZER(nmgr_state.ns_groups), + .ns_oc_event.ev_type = NMGR_OC_EVENT, + .ns_oc_timer.c_ev.ev_type = NMGR_OC_TIMER, + .ns_oc_timer.c_evq = &g_nmgr_evq +}; +struct os_eventq g_nmgr_evq; + +/* JSON buffer for NMGR task + */ + + +static void nmgr_oic_get(oc_request_t *request, oc_interface_mask_t interface); +static void nmgr_oic_put(oc_request_t *request, oc_interface_mask_t interface); + +int +nmgr_group_list_lock(void) +{ + int rc; + + if (!os_started()) { + return (0); + } + + rc = os_mutex_pend(&nmgr_state.ns_group_lock, OS_WAIT_FOREVER); + if (rc != 0) { + goto err; + } + + return (0); +err: + return (rc); +} + +int +nmgr_group_list_unlock(void) +{ + int rc; + + if (!os_started()) { + return (0); + } + + rc = os_mutex_release(&nmgr_state.ns_group_lock); + if (rc != 0) { + goto err; + } + + return (0); +err: + return (rc); +} + + +int +nmgr_group_register(struct nmgr_group *group) +{ + int rc; + + rc = nmgr_group_list_lock(); + if (rc != 0) { + goto err; + } + + STAILQ_INSERT_TAIL(&nmgr_state.ns_groups, group, ng_next); + + rc = nmgr_group_list_unlock(); + if (rc != 0) { + goto err; + } + + return (0); +err: + return (rc); +} + +static struct nmgr_group * +nmgr_find_group(uint16_t group_id) +{ + struct nmgr_group *group; + int rc; + + group = NULL; + + rc = nmgr_group_list_lock(); + if (rc != 0) { + goto err; + } + + STAILQ_FOREACH(group, &nmgr_state.ns_groups, ng_next) { + if (group->ng_group_id == group_id) { + break; + } + } + + rc = nmgr_group_list_unlock(); + if (rc != 0) { + goto err; + } + + return (group); +err: + return (NULL); +} + +static struct nmgr_handler * +nmgr_find_handler(uint16_t group_id, uint16_t handler_id) +{ + struct nmgr_group *group; + struct nmgr_handler *handler; + + group = nmgr_find_group(group_id); + if (!group) { + goto err; + } + + if (handler_id >= group->ng_handlers_count) { + goto err; + } + + handler = &group->ng_handlers[handler_id]; + + return (handler); +err: + return (NULL); +} + +int +nmgr_rsp_extend(struct nmgr_hdr *hdr, struct os_mbuf *rsp, void *data, + uint16_t len) +{ + int rc; + + rc = os_mbuf_append(rsp, data, len); + if (rc != 0) { + goto err; + } + hdr->nh_len += len; + + return (0); +err: + return (rc); +} + +static char +nmgr_jbuf_read_next(struct json_buffer *jb) +{ + struct nmgr_jbuf *njb; + char c; + + njb = (struct nmgr_jbuf *) jb; + + if (njb->njb_in_off + 1 > njb->njb_in_end) { + return '\0'; + } + + c = njb->njb_in[njb->njb_in_off]; + ++njb->njb_in_off; + + return (c); +} + +static char +nmgr_jbuf_read_prev(struct json_buffer *jb) +{ + struct nmgr_jbuf *njb; + char c; + + njb = (struct nmgr_jbuf *) jb; + + if (njb->njb_in_off == 0) { + return '\0'; + } + + --njb->njb_in_off; + c = njb->njb_in[njb->njb_in_off]; + + return (c); +} + +static int +nmgr_jbuf_readn(struct json_buffer *jb, char *buf, int size) +{ + struct nmgr_jbuf *njb; + int read; + int left; + + njb = (struct nmgr_jbuf *) jb; + + left = njb->njb_in_end - njb->njb_in_off; + read = size > left ? left : size; + + memcpy(buf, njb->njb_in + njb->njb_in_off, read); + + return (read); +} + +static int +nmgr_jbuf_write(void *arg, char *data, int len) +{ + struct nmgr_jbuf *njb; + int rc; + + njb = (struct nmgr_jbuf *) arg; + + if (njb->njb_out_off + len >= njb->njb_out_end) { + assert(0); + goto err; + } + memcpy(njb->njb_out + njb->njb_out_off, data, len); + njb->njb_out_off += len; + njb->njb_out[njb->njb_out_off] = '\0'; + + return (0); +err: + return (rc); +} + +static void +nmgr_jbuf_init(struct nmgr_jbuf *njb) +{ + memset(njb, 0, sizeof(*njb)); + + njb->njb_buf.jb_read_next = nmgr_jbuf_read_next; + njb->njb_buf.jb_read_prev = nmgr_jbuf_read_prev; + njb->njb_buf.jb_readn = nmgr_jbuf_readn; + njb->njb_enc.je_write = nmgr_jbuf_write; + njb->njb_enc.je_arg = njb; +} + +static void +nmgr_jbuf_setibuf(struct nmgr_jbuf *njb, char *ptr, uint16_t len) +{ + njb->njb_in_off = 0; + njb->njb_in_end = len; + njb->njb_in = ptr; + njb->njb_enc.je_wr_commas = 0; +} + +static void +nmgr_jbuf_setobuf(struct nmgr_jbuf *njb, char *ptr, uint16_t maxlen) +{ + njb->njb_out = ptr; + njb->njb_out_off = 0; + njb->njb_out_end = maxlen; + njb->njb_out[0] = '\0'; +} + +int +nmgr_jbuf_setoerr(struct nmgr_jbuf *njb, int errcode) +{ + struct json_value jv; + + json_encode_object_start(&njb->njb_enc); + JSON_VALUE_INT(&jv, errcode); + json_encode_object_entry(&njb->njb_enc, "rc", &jv); + json_encode_object_finish(&njb->njb_enc); + + return (0); +} + +static struct nmgr_handler * +nmgr_oic_find_handler(const char *q, int qlen) +{ + int grp; + int id; + char *str; + char *eptr; + int slen; + + slen = oc_ri_get_query_value(q, qlen, "gr", &str); + if (slen > 0) { + grp = strtoul(str, &eptr, 0); + if (*eptr != '\0' && *eptr != '&') { + return NULL; + } + } + slen = oc_ri_get_query_value(q, qlen, "id", &str); + if (slen > 0) { + id = strtoul(str, &eptr, 0); + if (*eptr != '\0' && *eptr != '&') { + return NULL; + } + } + return nmgr_find_handler(grp, id); +} + +static void +nmgr_oic_op(oc_request_t *req, oc_interface_mask_t mask, int isset) +{ + struct nmgr_state *ns = &nmgr_state; + struct nmgr_handler *handler; + oc_rep_t *data; + int rc; + + if (!req->query_len) { + goto bad_req; + } + + handler = nmgr_oic_find_handler(req->query, req->query_len); + if (!handler) { + goto bad_req; + } + + /* + * Setup state for JSON encoding. + */ + nmgr_jbuf_setobuf(&ns->ns_jbuf, ns->ns_rsp, sizeof(ns->ns_rsp)); + + data = req->request_payload; + if (data) { + if (data->type != STRING) { + goto bad_req; + } + nmgr_jbuf_setibuf(&ns->ns_jbuf, oc_string(data->value_string), + oc_string_len(data->value_string)); + } else { + nmgr_jbuf_setibuf(&ns->ns_jbuf, NULL, 0); + } + + if (!isset) { + if (handler->nh_read) { + rc = handler->nh_read(&ns->ns_jbuf); + } else { + goto bad_req; + } + } else { + if (handler->nh_write) { + rc = handler->nh_write(&ns->ns_jbuf); + } else { + goto bad_req; + } + } + if (rc) { + goto bad_req; + } + + oc_rep_start_root_object(); + switch (mask) { + case OC_IF_BASELINE: + oc_process_baseline_interface(req->resource); + case OC_IF_RW: + oc_rep_set_text_string(root, "key", ns->ns_rsp); + break; + default: + break; + } + oc_rep_end_root_object(); + oc_send_response(req, OC_STATUS_OK); + + return; +bad_req: + oc_send_response(req, OC_STATUS_BAD_REQUEST); +} + +static void +nmgr_oic_get(oc_request_t *req, oc_interface_mask_t mask) +{ + nmgr_oic_op(req, mask, 0); +} + +static void +nmgr_oic_put(oc_request_t *req, oc_interface_mask_t mask) +{ + nmgr_oic_op(req, mask, 1); +} + +static void +nmgr_app_init(void) +{ + oc_init_platform("MyNewt", NULL, NULL); + oc_add_device("/oic/d", "oic.d.light", "MynewtLed", "1.0", "1.0", NULL, + NULL); +} + +static void +nmgr_register_resources(void) +{ + uint8_t mode; + oc_resource_t *res = NULL; + char name[12]; + + snprintf(name, sizeof(name), "/nmgr"); + res = oc_new_resource(name, 1, 0); + oc_resource_bind_resource_type(res, "x.mynewt.nmgr"); + mode = OC_IF_RW; + oc_resource_bind_resource_interface(res, mode); + oc_resource_set_default_interface(res, mode); + oc_resource_set_discoverable(res); + oc_resource_set_request_handler(res, OC_GET, nmgr_oic_get); + oc_resource_set_request_handler(res, OC_PUT, nmgr_oic_put); + oc_add_resource(res); +} + +static const oc_handler_t nmgr_oc_handler = { + .init = nmgr_app_init, + .register_resources = nmgr_register_resources +}; + +void +oc_signal_main_loop(void) +{ + os_eventq_put(&g_nmgr_evq, &nmgr_state.ns_oc_event); +} + +void +nmgr_oic_task(void *arg) +{ + struct nmgr_state *ns = &nmgr_state; + struct os_event *ev; + struct os_callout_func *ocf; + os_time_t next_event; + + nmgr_jbuf_init(&ns->ns_jbuf); + + oc_main_init((oc_handler_t *)&nmgr_oc_handler); + while (1) { + ev = os_eventq_get(&g_nmgr_evq); + switch (ev->ev_type) { + case NMGR_OC_EVENT: + case NMGR_OC_TIMER: + next_event = oc_main_poll(); + if (next_event) { + os_callout_reset(&ns->ns_oc_timer, next_event - os_time_get()); + } else { + os_callout_stop(&ns->ns_oc_timer); + } + break; + case OS_EVENT_T_TIMER: + ocf = (struct os_callout_func *)ev; + ocf->cf_func(CF_ARG(ocf)); + break; + } + } +} + +int +nmgr_oic_init(uint8_t prio, os_stack_t *stack_ptr, uint16_t stack_len) +{ + struct nmgr_state *ns = &nmgr_state; + int rc; + + os_eventq_init(&g_nmgr_evq); + + rc = os_task_init(&ns->ns_task, "newtmgr_oic", nmgr_oic_task, NULL, prio, + OS_WAIT_FOREVER, stack_ptr, stack_len); + if (rc != 0) { + goto err; + } + + rc = nmgr_os_groups_register(); + if (rc != 0) { + goto err; + } + + return (0); +err: + return (rc); +}