Skip to content

Commit

Permalink
examples/gcoap: split client and server implementation
Browse files Browse the repository at this point in the history
Move client and server side implementations into separate files to
increase readability. Also get rid of a goto.
  • Loading branch information
maribu committed Jan 4, 2022
1 parent 3c5c351 commit 8002c87
Show file tree
Hide file tree
Showing 8 changed files with 290 additions and 170 deletions.
180 changes: 15 additions & 165 deletions examples/gcoap/gcoap_cli.c → examples/gcoap/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,92 +23,32 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "fmt.h"
#include "net/gcoap.h"
#include "net/utils.h"
#include "od.h"
#include "fmt.h"

#include "gcoap_example.h"

#define ENABLE_DEBUG 0
#include "debug.h"

#if IS_USED(MODULE_GCOAP_DTLS)
#include "net/credman.h"
#include "net/dsm.h"
#include "tinydtls_keys.h"

/* Example credential tag for credman. Tag together with the credential type needs to be unique. */
#define GCOAP_DTLS_CREDENTIAL_TAG 10

static const uint8_t psk_id_0[] = PSK_DEFAULT_IDENTITY;
static const uint8_t psk_key_0[] = PSK_DEFAULT_KEY;
static const credman_credential_t credential = {
.type = CREDMAN_TYPE_PSK,
.tag = GCOAP_DTLS_CREDENTIAL_TAG,
.params = {
.psk = {
.key = { .s = psk_key_0, .len = sizeof(psk_key_0) - 1, },
.id = { .s = psk_id_0, .len = sizeof(psk_id_0) - 1, },
}
},
};
#endif

static bool _proxied = false;
static sock_udp_ep_t _proxy_remote;
static char proxy_uri[64];

static ssize_t _encode_link(const coap_resource_t *resource, char *buf,
size_t maxlen, coap_link_encoder_ctx_t *context);
static void _resp_handler(const gcoap_request_memo_t *memo, coap_pkt_t* pdu,
const sock_udp_ep_t *remote);
static ssize_t _stats_handler(coap_pkt_t* pdu, uint8_t *buf, size_t len, void *ctx);
static ssize_t _riot_board_handler(coap_pkt_t* pdu, uint8_t *buf, size_t len, void *ctx);

/* CoAP resources. Must be sorted by path (ASCII order). */
static const coap_resource_t _resources[] = {
{ "/cli/stats", COAP_GET | COAP_PUT, _stats_handler, NULL },
{ "/riot/board", COAP_GET, _riot_board_handler, NULL },
};

static const char *_link_params[] = {
";ct=0;rt=\"count\";obs",
NULL
};

static gcoap_listener_t _listener = {
&_resources[0],
ARRAY_SIZE(_resources),
_encode_link,
NULL,
NULL
};

/* Retain request path to re-request if response includes block. User must not
* start a new request (with a new path) until any blockwise transfer
* completes or times out. */
#define _LAST_REQ_PATH_MAX (64)
static char _last_req_path[_LAST_REQ_PATH_MAX];

/* Counts requests sent by CLI. */
static uint16_t req_count = 0;

/* Adds link format params to resource list */
static ssize_t _encode_link(const coap_resource_t *resource, char *buf,
size_t maxlen, coap_link_encoder_ctx_t *context) {
ssize_t res = gcoap_encode_link(resource, buf, maxlen, context);
if (res > 0) {
if (_link_params[context->link_pos]
&& (strlen(_link_params[context->link_pos]) < (maxlen - res))) {
if (buf) {
memcpy(buf+res, _link_params[context->link_pos],
strlen(_link_params[context->link_pos]));
}
return res + strlen(_link_params[context->link_pos]);
}
}

return res;
}
uint16_t req_count = 0;

/*
* Response callback.
Expand Down Expand Up @@ -201,66 +141,6 @@ static void _resp_handler(const gcoap_request_memo_t *memo, coap_pkt_t* pdu,
}
}

/*
* Server callback for /cli/stats. Accepts either a GET or a PUT.
*
* GET: Returns the count of packets sent by the CLI.
* PUT: Updates the count of packets. Rejects an obviously bad request, but
* allows any two byte value for example purposes. Semantically, the only
* valid action is to set the value to 0.
*/
static ssize_t _stats_handler(coap_pkt_t* pdu, uint8_t *buf, size_t len, void *ctx)
{
(void)ctx;

/* read coap method type in packet */
unsigned method_flag = coap_method2flag(coap_get_code_detail(pdu));

switch (method_flag) {
case COAP_GET:
gcoap_resp_init(pdu, buf, len, COAP_CODE_CONTENT);
coap_opt_add_format(pdu, COAP_FORMAT_TEXT);
size_t resp_len = coap_opt_finish(pdu, COAP_OPT_FINISH_PAYLOAD);

/* write the response buffer with the request count value */
resp_len += fmt_u16_dec((char *)pdu->payload, req_count);
return resp_len;

case COAP_PUT:
/* convert the payload to an integer and update the internal
value */
if (pdu->payload_len <= 5) {
char payload[6] = { 0 };
memcpy(payload, (char *)pdu->payload, pdu->payload_len);
req_count = (uint16_t)strtoul(payload, NULL, 10);
return gcoap_response(pdu, buf, len, COAP_CODE_CHANGED);
}
else {
return gcoap_response(pdu, buf, len, COAP_CODE_BAD_REQUEST);
}
}

return 0;
}

static ssize_t _riot_board_handler(coap_pkt_t *pdu, uint8_t *buf, size_t len, void *ctx)
{
(void)ctx;
gcoap_resp_init(pdu, buf, len, COAP_CODE_CONTENT);
coap_opt_add_format(pdu, COAP_FORMAT_TEXT);
size_t resp_len = coap_opt_finish(pdu, COAP_OPT_FINISH_PAYLOAD);

/* write the RIOT board name in the response buffer */
if (pdu->payload_len >= strlen(RIOT_BOARD)) {
memcpy(pdu->payload, RIOT_BOARD, strlen(RIOT_BOARD));
return resp_len + strlen(RIOT_BOARD);
}
else {
puts("gcoap_cli: msg buffer too small");
return gcoap_response(pdu, buf, len, COAP_CODE_INTERNAL_SERVER_ERROR);
}
}

static bool _parse_endpoint(sock_udp_ep_t *remote,
const char *addr_str, const char *port_str)
{
Expand Down Expand Up @@ -307,6 +187,12 @@ static size_t _send(uint8_t *buf, size_t len, char *addr_str, char *port_str)
return bytes_sent;
}

static int _print_usage(char **argv)
{
printf("usage: %s <get|post|put|ping|proxy|info>\n", argv[0]);
return 1;
}

int gcoap_cli_cmd(int argc, char **argv)
{
/* Ordered like the RFC method code numbers, but off by 1. GET is code 0. */
Expand All @@ -317,7 +203,7 @@ int gcoap_cli_cmd(int argc, char **argv)

if (argc == 1) {
/* show help for main commands */
goto end;
return _print_usage(argv);
}

if (strcmp(argv[1], "info") == 0) {
Expand Down Expand Up @@ -376,7 +262,7 @@ int gcoap_cli_cmd(int argc, char **argv)
}
}
if (code_pos == -1) {
goto end;
return _print_usage(argv);
}

/* parse options */
Expand Down Expand Up @@ -447,22 +333,7 @@ int gcoap_cli_cmd(int argc, char **argv)
}
else {
/* send Observe notification for /cli/stats */
switch (gcoap_obs_init(&pdu, &buf[0], CONFIG_GCOAP_PDU_BUF_SIZE,
&_resources[0])) {
case GCOAP_OBS_INIT_OK:
DEBUG("gcoap_cli: creating /cli/stats notification\n");
coap_opt_add_format(&pdu, COAP_FORMAT_TEXT);
len = coap_opt_finish(&pdu, COAP_OPT_FINISH_PAYLOAD);
len += fmt_u16_dec((char *)pdu.payload, req_count);
gcoap_obs_send(&buf[0], len, &_resources[0]);
break;
case GCOAP_OBS_INIT_UNUSED:
DEBUG("gcoap_cli: no observer for /cli/stats\n");
break;
case GCOAP_OBS_INIT_ERR:
DEBUG("gcoap_cli: error initializing /cli/stats notification\n");
break;
}
notify_observers();
}
return 0;
}
Expand All @@ -475,26 +346,5 @@ int gcoap_cli_cmd(int argc, char **argv)
return 1;
}

end:
printf("usage: %s <get|post|put|ping|proxy|info>\n", argv[0]);
return 1;
}

void gcoap_cli_init(void)
{
#if IS_USED(MODULE_GCOAP_DTLS)
int res = credman_add(&credential);
if (res < 0 && res != CREDMAN_EXIST) {
/* ignore duplicate credentials */
printf("gcoap: cannot add credential to system: %d\n", res);
return;
}
sock_dtls_t *gcoap_sock_dtls = gcoap_get_sock_dtls();
res = sock_dtls_add_credential(gcoap_sock_dtls, GCOAP_DTLS_CREDENTIAL_TAG);
if (res < 0) {
printf("gcoap: cannot add credential to DTLS sock: %d\n", res);
}
#endif

gcoap_register_listener(&_listener);
return _print_usage(argv);
}
65 changes: 65 additions & 0 deletions examples/gcoap/gcoap_example.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Copyright (C) 2020 Otto-von-Guericke-Universität Magdeburg
*
* This file is subject to the terms and conditions of the GNU Lesser General
* Public License v2.1. See the file LICENSE in the top level directory for more
* details.
*/

/**
* @ingroup examples
* @{
*
* @file
* @brief gcoap example
*
* @author Ken Bannister <kb2ma@runbox.com>
*/

#ifndef GCOAP_EXAMPLE_H
#define GCOAP_EXAMPLE_H

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "fmt.h"
#include "net/gcoap.h"
#include "net/utils.h"
#include "od.h"

#ifdef __cplusplus
extern "C" {
#endif

extern uint16_t req_count; /**< Counts requests sent by CLI. */

/**
* @brief Shell interface exposing the client side features of gcoap
* @param argc Number of shell arguments (including shell command name)
* @param argv Shell argument values (including shell command name)
* @return Exit status of the shell command
*/
int gcoap_cli_cmd(int argc, char **argv);

/**
* @brief Registers the CoAP resources exposed in the example app
*
* Run this exactly one during startup.
*/
void server_init(void);

/**
* @brief Notifies all observers registered to /cli/stats - if any
*
* Call this whenever the count of successfully send client requests changes
*/
void notify_observers(void);

#ifdef __cplusplus
}
#endif

#endif /* CC110X_H */
/** @} */
7 changes: 3 additions & 4 deletions examples/gcoap/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,11 @@
#include "net/gcoap.h"
#include "shell.h"

#include "gcoap_example.h"

#define MAIN_QUEUE_SIZE (4)
static msg_t _main_msg_queue[MAIN_QUEUE_SIZE];

extern int gcoap_cli_cmd(int argc, char **argv);
extern void gcoap_cli_init(void);

static const shell_command_t shell_commands[] = {
{ "coap", "CoAP example", gcoap_cli_cmd },
{ NULL, NULL, NULL }
Expand All @@ -39,7 +38,7 @@ int main(void)
{
/* for the thread running the shell */
msg_init_queue(_main_msg_queue, MAIN_QUEUE_SIZE);
gcoap_cli_init();
server_init();
puts("gcoap example app");

/* start shell */
Expand Down
Loading

0 comments on commit 8002c87

Please sign in to comment.