blob: 460cb426c27145814de0c39ed88d968ed3d79f65 [file] [log] [blame]
/*
* Copyright (c) 2016 Intel Corporation
*
* Licensed 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 <errno.h>
#include <stdio.h>
#include <zephyr.h>
#include <misc/byteorder.h>
#include <net/net_core.h>
#include <net/net_socket.h>
#include <net/ip_buf.h>
#include <net/net_ip.h>
#if defined(CONFIG_NET_TESTING)
#include <net_testing.h>
#endif
#include <zoap.h>
#define MY_COAP_PORT 5683
#define STACKSIZE 2000
#define ALL_NODES_LOCAL_COAP_MCAST \
{ { { 0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xfd } } }
char fiberStack[STACKSIZE];
static struct net_context *context;
static int test_del(struct zoap_resource *resource,
struct zoap_packet *request,
const uip_ipaddr_t *addr,
uint16_t port)
{
struct net_buf *buf;
struct zoap_packet response;
uint8_t code, type, *payload;
uint16_t id, len;
int r;
payload = zoap_packet_get_payload(request, &len);
if (!payload) {
printf("packet without payload");
return -EINVAL;
}
code = zoap_header_get_code(request);
type = zoap_header_get_type(request);
id = zoap_header_get_id(request);
NET_INFO("*******\n");
NET_INFO("type: %u code %u id %u\n", type, code, id);
NET_INFO("*******\n");
/* Re-using the request buffer for the response */
buf = request->buf;
r = zoap_packet_init(&response, buf);
if (r < 0) {
return -EINVAL;
}
/* FIXME: Could be that zoap_packet_init() sets some defaults */
zoap_header_set_version(&response, 1);
zoap_header_set_type(&response, ZOAP_TYPE_ACK);
zoap_header_set_code(&response, ZOAP_RESPONSE_CODE_DELETED);
zoap_header_set_id(&response, id);
return net_reply(context, buf);
}
static int test_put(struct zoap_resource *resource,
struct zoap_packet *request,
const uip_ipaddr_t *addr,
uint16_t port)
{
struct net_buf *buf;
struct zoap_packet response;
uint8_t *payload, code, type;
uint16_t len, id;
int r;
payload = zoap_packet_get_payload(request, &len);
if (!payload) {
printf("packet without payload");
return -EINVAL;
}
code = zoap_header_get_code(request);
type = zoap_header_get_type(request);
id = zoap_header_get_id(request);
NET_INFO("*******\n");
NET_INFO("type: %u code %u id %u\n", type, code, id);
NET_INFO("*******\n");
/* Re-using the request buffer for the response */
buf = request->buf;
r = zoap_packet_init(&response, buf);
if (r < 0) {
return -EINVAL;
}
/* FIXME: Could be that zoap_packet_init() sets some defaults */
zoap_header_set_version(&response, 1);
zoap_header_set_type(&response, ZOAP_TYPE_ACK);
zoap_header_set_code(&response, ZOAP_RESPONSE_CODE_CHANGED);
zoap_header_set_id(&response, id);
return net_reply(context, buf);
}
static int test_post(struct zoap_resource *resource,
struct zoap_packet *request,
const uip_ipaddr_t *addr,
uint16_t port)
{
struct net_buf *buf;
struct zoap_packet response;
uint8_t *payload, code, type;
uint16_t len, id;
int r;
payload = zoap_packet_get_payload(request, &len);
if (!payload) {
printf("packet without payload");
return -EINVAL;
}
code = zoap_header_get_code(request);
type = zoap_header_get_type(request);
id = zoap_header_get_id(request);
NET_INFO("*******\n");
NET_INFO("type: %u code %u id %u\n", type, code, id);
NET_INFO("*******\n");
/* Re-using the request buffer for the response */
buf = request->buf;
r = zoap_packet_init(&response, buf);
if (r < 0) {
return -EINVAL;
}
/* FIXME: Could be that zoap_packet_init() sets some defaults */
zoap_header_set_version(&response, 1);
zoap_header_set_type(&response, ZOAP_TYPE_ACK);
zoap_header_set_code(&response, ZOAP_RESPONSE_CODE_CREATED);
zoap_header_set_id(&response, id);
return net_reply(context, buf);
}
static int piggyback_get(struct zoap_resource *resource,
struct zoap_packet *request,
const uip_ipaddr_t *addr,
uint16_t port)
{
struct net_buf *buf;
struct zoap_packet response;
uint8_t *payload, code, type;
uint16_t len, id;
int r;
payload = zoap_packet_get_payload(request, &len);
if (!payload) {
printf("packet without payload");
return -EINVAL;
}
code = zoap_header_get_code(request);
type = zoap_header_get_type(request);
id = zoap_header_get_id(request);
NET_INFO("*******\n");
NET_INFO("type: %u code %u id %u\n", type, code, id);
NET_INFO("*******\n");
/* Re-using the request buffer for the response */
buf = request->buf;
r = zoap_packet_init(&response, buf);
if (r < 0) {
return -EINVAL;
}
/* FIXME: Could be that zoap_packet_init() sets some defaults */
zoap_header_set_version(&response, 1);
zoap_header_set_type(&response, ZOAP_TYPE_ACK);
zoap_header_set_code(&response, ZOAP_RESPONSE_CODE_CONTENT);
zoap_header_set_id(&response, id);
payload = zoap_packet_get_payload(&response, &len);
if (!payload) {
return -EINVAL;
}
/* The response that coap-client expects */
r = snprintf((char *) payload, len, "Type: %u\nCode: %u\nMID: %u\n",
type, code, id);
if (r < 0 || r > len) {
return -EINVAL;
}
r = zoap_packet_set_used(&response, r);
if (r) {
return -EINVAL;
}
return net_reply(context, buf);
}
static int query_get(struct zoap_resource *resource,
struct zoap_packet *request,
const uip_ipaddr_t *addr,
uint16_t port)
{
struct zoap_option options[4];
struct net_buf *buf;
struct zoap_packet response;
uint8_t *payload, code, type;
uint16_t len, id;
int i, r;
payload = zoap_packet_get_payload(request, &len);
if (!payload) {
printf("packet without payload");
return -EINVAL;
}
code = zoap_header_get_code(request);
type = zoap_header_get_type(request);
id = zoap_header_get_id(request);
r = zoap_find_options(request, ZOAP_OPTION_URI_QUERY, options, 4);
if (r <= 0) {
return -EINVAL;
}
NET_INFO("*******\n");
NET_INFO("type: %u code %u id %u\n", type, code, id);
NET_INFO("num queries: %d\n", r);
for (i = 0; i < r; i++) {
char str[16];
if (options[i].len + 1 > sizeof(str)) {
NET_INFO("Unexpected length of query: "
"%d (expected %zu)\n",
options[i].len, sizeof(str));
break;
}
memcpy(str, options[i].value, options[i].len);
str[options[i].len] = '\0';
NET_INFO("query[%d]: %s\n", i + 1, str);
}
NET_INFO("*******\n");
/* Re-using the request buffer for the response */
buf = request->buf;
r = zoap_packet_init(&response, buf);
if (r < 0) {
return -EINVAL;
}
/* FIXME: Could be that zoap_packet_init() sets some defaults */
zoap_header_set_version(&response, 1);
zoap_header_set_type(&response, ZOAP_TYPE_ACK);
zoap_header_set_code(&response, ZOAP_RESPONSE_CODE_CONTENT);
zoap_header_set_id(&response, id);
payload = zoap_packet_get_payload(&response, &len);
if (!payload) {
return -EINVAL;
}
/* The response that coap-client expects */
r = snprintf((char *) payload, len, "Type: %u\nCode: %u\nMID: %u\n",
type, code, id);
if (r < 0 || r > len) {
return -EINVAL;
}
r = zoap_packet_set_used(&response, r);
if (r) {
return -EINVAL;
}
return net_reply(context, buf);
}
static const char * const test_path[] = { "test", NULL };
static const char * const segments_path[] = { "seg1", "seg2", "seg3", NULL };
static const char * const query_path[] = { "query", NULL };
static struct zoap_resource resources[] = {
{ .get = piggyback_get,
.post = test_post,
.del = test_del,
.put = test_put,
.path = test_path },
{ .get = piggyback_get,
.path = segments_path,
},
{ .get = query_get,
.path = query_path,
},
{ },
};
static void udp_receive(void)
{
struct net_buf *buf;
struct zoap_packet request;
int r;
while (true) {
struct uip_conn *conn;
buf = net_receive(context, TICKS_UNLIMITED);
if (!buf) {
continue;
}
r = zoap_packet_parse(&request, buf);
if (r < 0) {
printf("Invalid data received (%d)\n", r);
continue;
}
conn = uip_conn(buf);
r = zoap_handle_request(&request, resources, &conn->ripaddr,
sys_be16_to_cpu(conn->rport));
if (r < 0) {
printf("No handler for such request (%d)\n", r);
continue;
}
}
}
void main(void)
{
static struct net_addr mcast_addr = {
.in6_addr = ALL_NODES_LOCAL_COAP_MCAST,
.family = AF_INET6 };
static struct net_addr any_addr = { .in6_addr = IN6ADDR_ANY_INIT,
.family = AF_INET6 };
net_init();
#if defined(CONFIG_NET_TESTING)
net_testing_setup();
#endif
context = net_context_get(IPPROTO_UDP, &any_addr, 0,
&mcast_addr, MY_COAP_PORT);
task_fiber_start(&fiberStack[0], STACKSIZE,
(nano_fiber_entry_t) udp_receive, 0, 0, 7, 0);
}