Commit 0b4d690f authored by Anon Mall's avatar Anon Mall
Browse files

finished coap frontend

parent d4b168ae
......@@ -3,26 +3,364 @@
*
* Created on: 13.09.2017
* Author: geith
* Author: mall
*/
#include <iostream>
#include <unistd.h>
#include <cassert>
extern "C" {
#include <netdb.h>
}
#include "coap-frontend.h"
#include "desk-controller.h"
#include <iostream>
#ifdef __GNUC__
#define UNUSED_PARAM __attribute__((unused))
#else /* not a GCC */
#define UNUSED_PARAM
#endif /* GCC */
#include <unistd.h>
#define MIN(X,Y) ((X) < (Y) ? (X) : (Y))
#define INDEX "Index...\n" \
"...\n\n"
using namespace std;
using namespace desk;
CoapFrontend::CoapFrontend(Controller& controller, uint16_t port):
Frontend(controller),
AvahiService("desk", "_coap._udp", port),
thread(&CoapFrontend::run, this),
m_port(port)
map<coap_resource_t*, CoapFrontend*> CoapFrontend::s_callbackMap;
CoapFrontend::CoapFrontend(Controller &controller, uint16_t port) : Frontend(controller),
m_controller(controller),
AvahiService("desk", "_coap._udp", port),
thread(&CoapFrontend::run, this),
m_port(port),
m_async(NULL)
{
m_ccontext = get_context("::", port);
if (!m_ccontext)
throw CoapException("Context could not be initialized");
init_resources(m_ccontext);
}
void CoapFrontend::s_get_index(coap_context_t *ctx UNUSED_PARAM,
struct coap_resource_t *resource UNUSED_PARAM,
const coap_endpoint_t *local_interface UNUSED_PARAM,
coap_address_t *peer UNUSED_PARAM,
coap_pdu_t *request UNUSED_PARAM,
str *token UNUSED_PARAM,
coap_pdu_t *response)
{
CoapFrontend *cf = s_callbackMap.at(resource);
cf->hnd_get_index(ctx, resource, local_interface, peer, request, token, response);
}
void CoapFrontend::hnd_get_index(coap_context_t *ctx UNUSED_PARAM,
struct coap_resource_t *resource UNUSED_PARAM,
const coap_endpoint_t *local_interface UNUSED_PARAM,
coap_address_t *peer UNUSED_PARAM,
coap_pdu_t *request UNUSED_PARAM,
str *token UNUSED_PARAM,
coap_pdu_t *response)
{
unsigned char buf[3];
printf("%s: #1\n", __func__);
response->hdr->code = COAP_RESPONSE_CODE(205);
coap_add_option(response,
COAP_OPTION_CONTENT_TYPE,
coap_encode_var_bytes(buf, COAP_MEDIATYPE_TEXT_PLAIN), buf);
coap_add_option(response,
COAP_OPTION_MAXAGE,
coap_encode_var_bytes(buf, 0x2ffff), buf);
coap_add_data(response, strlen(INDEX), (unsigned char *)INDEX);
}
void CoapFrontend::s_get_height(coap_context_t *ctx UNUSED_PARAM,
struct coap_resource_t *resource UNUSED_PARAM,
const coap_endpoint_t *local_interface UNUSED_PARAM,
coap_address_t *peer UNUSED_PARAM,
coap_pdu_t *request UNUSED_PARAM,
str *token UNUSED_PARAM,
coap_pdu_t *response)
{
CoapFrontend *cf = s_callbackMap.at(resource);
cf->hnd_get_height(ctx, resource, local_interface, peer, request, token, response);
}
void CoapFrontend::hnd_get_height(coap_context_t *ctx,
struct coap_resource_t *resource,
const coap_endpoint_t *local_interface UNUSED_PARAM,
coap_address_t *peer,
coap_pdu_t *request,
str *token,
coap_pdu_t *response)
{
coap_opt_iterator_t opt_iter;
coap_opt_t *option;
unsigned char buf[40];
size_t len;
time_t now;
coap_tick_t t;
response->hdr->code = COAP_RESPONSE_CODE(205);
if (coap_find_observer(resource, peer, token))
{
coap_add_option(response,
COAP_OPTION_OBSERVE,
coap_encode_var_bytes(buf, ctx->observe), buf);
}
coap_add_option(response,
COAP_OPTION_CONTENT_FORMAT,
coap_encode_var_bytes(buf, COAP_MEDIATYPE_TEXT_PLAIN), buf);
len = snprintf((char*)buf, sizeof(buf), "%d", m_controller.getHeight());
coap_add_data(response, len, buf);
}
void CoapFrontend::s_put_height(coap_context_t *ctx UNUSED_PARAM,
struct coap_resource_t *resource UNUSED_PARAM,
const coap_endpoint_t *local_interface UNUSED_PARAM,
coap_address_t *peer UNUSED_PARAM,
coap_pdu_t *request UNUSED_PARAM,
str *token UNUSED_PARAM,
coap_pdu_t *response)
{
CoapFrontend *cf = s_callbackMap.at(resource);
cf->hnd_put_height(ctx, resource, local_interface, peer, request, token, response);
}
void CoapFrontend::hnd_put_height(coap_context_t *ctx UNUSED_PARAM,
struct coap_resource_t *resource UNUSED_PARAM,
const coap_endpoint_t *local_interface UNUSED_PARAM,
coap_address_t *peer UNUSED_PARAM,
coap_pdu_t *request,
str *token UNUSED_PARAM,
coap_pdu_t *response)
{
coap_tick_t t;
size_t size;
unsigned char *data;
int val;
unsigned char buf[20];
resource->dirty = 1;
coap_get_data(request, &size, &data);
strncpy((char*)buf, (const char*) data, MIN(size, sizeof(buf)));
if (size != 0)
{
char *endptr;
val = strtol((const char*)buf, &endptr, 10);
if ((char *)buf == endptr)
{
response->hdr->code = COAP_RESPONSE_CODE(415);
}
else
{
m_controller.setHeight(val);
response->hdr->code = COAP_RESPONSE_CODE(204);
}
}
else
{
response->hdr->code = COAP_RESPONSE_CODE(400);
}
}
void CoapFrontend::s_get_offset(coap_context_t *ctx UNUSED_PARAM,
struct coap_resource_t *resource UNUSED_PARAM,
const coap_endpoint_t *local_interface UNUSED_PARAM,
coap_address_t *peer UNUSED_PARAM,
coap_pdu_t *request UNUSED_PARAM,
str *token UNUSED_PARAM,
coap_pdu_t *response)
{
CoapFrontend *cf = s_callbackMap.at(resource);
cf->hnd_get_offset(ctx, resource, local_interface, peer, request, token, response);
}
void CoapFrontend::hnd_get_offset(coap_context_t *ctx,
struct coap_resource_t *resource,
const coap_endpoint_t *local_interface UNUSED_PARAM,
coap_address_t *peer,
coap_pdu_t *request,
str *token,
coap_pdu_t *response)
{
coap_opt_iterator_t opt_iter;
coap_opt_t *option;
unsigned char buf[40];
size_t len;
time_t now;
coap_tick_t t;
response->hdr->code = COAP_RESPONSE_CODE(205);
if (coap_find_observer(resource, peer, token))
{
coap_add_option(response,
COAP_OPTION_OBSERVE,
coap_encode_var_bytes(buf, ctx->observe), buf);
}
coap_add_option(response,
COAP_OPTION_CONTENT_FORMAT,
coap_encode_var_bytes(buf, COAP_MEDIATYPE_TEXT_PLAIN), buf);
len = snprintf((char*)buf, sizeof(buf), "%d", m_controller.getOffset());
cout << "offset: " << m_controller.getOffset() << endl;
coap_add_data(response, len, buf);
}
void CoapFrontend::s_put_offset(coap_context_t *ctx UNUSED_PARAM,
struct coap_resource_t *resource UNUSED_PARAM,
const coap_endpoint_t *local_interface UNUSED_PARAM,
coap_address_t *peer UNUSED_PARAM,
coap_pdu_t *request UNUSED_PARAM,
str *token UNUSED_PARAM,
coap_pdu_t *response)
{
CoapFrontend *cf = s_callbackMap.at(resource);
cf->hnd_put_offset(ctx, resource, local_interface, peer, request, token, response);
}
void CoapFrontend::hnd_put_offset(coap_context_t *ctx UNUSED_PARAM,
struct coap_resource_t *resource UNUSED_PARAM,
const coap_endpoint_t *local_interface UNUSED_PARAM,
coap_address_t *peer UNUSED_PARAM,
coap_pdu_t *request,
str *token UNUSED_PARAM,
coap_pdu_t *response)
{
coap_tick_t t;
size_t size;
unsigned char *data;
int val;
unsigned char buf[20];
resource->dirty = 1;
coap_get_data(request, &size, &data);
strncpy((char*)buf, (const char*) data, MIN(size, sizeof(buf)));
if (size != 0)
{
char *endptr;
val = strtol((const char*)buf, &endptr, 10);
if ((char *)buf == endptr)
{
response->hdr->code = COAP_RESPONSE_CODE(415);
}
else
{
m_controller.setOffset(val);
response->hdr->code = COAP_RESPONSE_CODE(204);
}
}
else
{
response->hdr->code = COAP_RESPONSE_CODE(400);
}
}
void CoapFrontend::init_resources(coap_context_t *ctx)
{
coap_resource_t *root;
coap_resource_t *height;
coap_resource_t *offset;
// root
root = coap_resource_init(NULL, 0, 0);
s_callbackMap.emplace(root, this);
coap_register_handler(root, COAP_REQUEST_GET, s_get_index);
coap_add_attr(root, (unsigned char *)"ct", 2, (unsigned char *)"0", 1, 0);
coap_add_attr(root, (unsigned char *)"title", 5, (unsigned char *)"\"General Info\"", 14, 0);
coap_add_resource(ctx, root);
// height
height = coap_resource_init((unsigned char *)"height", 6, COAP_RESOURCE_FLAGS_NOTIFY_CON);
s_callbackMap.emplace(height, this);
coap_register_handler(height, COAP_REQUEST_GET, s_get_height);
coap_register_handler(height, COAP_REQUEST_PUT, s_put_height);
// attributes...
height->observable = 1;
coap_add_resource(ctx, height);
m_res_height = height;
// offset
offset = coap_resource_init((unsigned char *)"offset", 6, COAP_RESOURCE_FLAGS_NOTIFY_CON);
s_callbackMap.emplace(offset, this);
coap_register_handler(offset, COAP_REQUEST_GET, s_get_offset);
coap_register_handler(offset, COAP_REQUEST_PUT, s_put_offset);
// attributes...
offset->observable = 1;
coap_add_resource(ctx, offset);
m_res_offset = offset;
}
coap_context_t *
CoapFrontend::get_context(const char *node, int port)
{
coap_context_t *ctx = NULL;
int s;
struct addrinfo hints;
struct addrinfo *result, *rp;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
hints.ai_socktype = SOCK_DGRAM; /* Coap uses UDP */
hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
s = getaddrinfo(node, to_string(port).c_str(), &hints, &result);
if (s != 0)
{
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
return NULL;
}
/* iterate through results until success */
for (rp = result; rp != NULL; rp = rp->ai_next)
{
coap_address_t addr;
if (rp->ai_addrlen <= sizeof(addr.addr))
{
coap_address_init(&addr);
addr.size = rp->ai_addrlen;
memcpy(&addr.addr, rp->ai_addr, rp->ai_addrlen);
ctx = coap_new_context(&addr);
if (ctx)
{
/* TODO: output address:port for successful binding */
goto finish;
}
}
}
fprintf(stderr, "no context available for interface '%s'\n", node);
finish:
freeaddrinfo(result);
return ctx;
}
CoapFrontend::~CoapFrontend()
......@@ -36,10 +374,10 @@ CoapFrontend::~CoapFrontend()
*/
}
void
CoapFrontend::notify(DeskNotification& notification)
void CoapFrontend::notify(DeskNotification &notification)
{
switch(notification.type){
switch (notification.type)
{
case DeskNotification::Type::current_height:
cout << __PRETTY_FUNCTION__ << ": height=" << notification.value << endl;
break;
......@@ -52,13 +390,97 @@ CoapFrontend::notify(DeskNotification& notification)
}
}
void
CoapFrontend::run()
void CoapFrontend::check_async(coap_context_t *ctx,
const coap_endpoint_t *local_if,
coap_tick_t now) {
coap_pdu_t *response;
coap_async_state_t *tmp;
size_t size = sizeof(coap_hdr_t) + 13;
if (!m_async || now < m_async->created + (unsigned long)m_async->appdata)
return;
response = coap_pdu_init(m_async->flags & COAP_ASYNC_CONFIRM
? COAP_MESSAGE_CON
: COAP_MESSAGE_NON,
COAP_RESPONSE_CODE(205), 0, size);
if (!response) {
debug("check_async: insufficient memory, we'll try later\n");
m_async->appdata =
(void *)((unsigned long)m_async->appdata + 15 * COAP_TICKS_PER_SECOND);
return;
}
response->hdr->id = coap_new_message_id(ctx);
if (m_async->tokenlen)
coap_add_token(response, m_async->tokenlen, m_async->token);
coap_add_data(response, 4, (unsigned char *)"done");
if (coap_send(ctx, local_if, &m_async->peer, response) == COAP_INVALID_TID) {
debug("check_async: cannot send response for message %d\n",
response->hdr->id);
}
coap_delete_pdu(response);
coap_remove_async(ctx, m_async->id, &tmp);
coap_free_async(m_async);
m_async = NULL;
}
void CoapFrontend::run()
{
while(true){
cout << __PRETTY_FUNCTION__ << ": tbd..." << endl;
cout << "Starting CoapFrontend thread" << endl;
coap_queue_t *nextpdu;
coap_tick_t now;
struct timeval tv, *timeout;
int result;
struct coap_resource_t *time_resource = NULL;
sleep(1);
while (true)
{
FD_ZERO(&m_readfds);
FD_SET( m_ccontext->sockfd, &m_readfds );
nextpdu = coap_peek_next( m_ccontext );
coap_ticks(&now);
while (nextpdu && nextpdu->t <= now - m_ccontext->sendqueue_basetime) {
coap_retransmit( m_ccontext, coap_pop_next( m_ccontext ) );
nextpdu = coap_peek_next( m_ccontext );
}
if ( nextpdu && nextpdu->t <= COAP_RESOURCE_CHECK_TIME ) {
/* set timeout if there is a pdu to send before our automatic timeout occurs */
tv.tv_usec = ((nextpdu->t) % COAP_TICKS_PER_SECOND) * 1000000 / COAP_TICKS_PER_SECOND;
tv.tv_sec = (nextpdu->t) / COAP_TICKS_PER_SECOND;
timeout = &tv;
} else {
tv.tv_usec = 0;
tv.tv_sec = COAP_RESOURCE_CHECK_TIME;
timeout = &tv;
}
result = select( FD_SETSIZE, &m_readfds, 0, 0, timeout );
if ( result < 0 ) { /* error */
if (errno != EINTR)
perror("select");
} else if ( result > 0 ) { /* read from socket */
if ( FD_ISSET( m_ccontext->sockfd, &m_readfds ) ) {
coap_read( m_ccontext ); /* read received data */
/* coap_dispatch( ctx ); /\* and dispatch PDUs from receivequeue *\/ */
}
} else { /* timeout */
if (time_resource) {
time_resource->dirty = 1;
}
}
check_async(m_ccontext, m_ccontext->endpoint, now);
coap_check_notify(m_ccontext);
//cout << __PRETTY_FUNCTION__ << ": tbd..." << endl;
sleep(1);
}
}
......@@ -11,7 +11,13 @@
#include "desk-frontend.h"
#include "avahi-service.h"
#define WITH_POSIX
#include "coap.h"
#include <thread>
#include <exception>
#include <map>
#include <utility>
#include <avahi-client/client.h>
#include <avahi-client/publish.h>
......@@ -19,6 +25,21 @@
namespace desk{
class CoapException: public std::exception{
public:
CoapException(std::string msg) _GLIBCXX_USE_NOEXCEPT
: m_msg(msg){ }
virtual const char* what()
const _GLIBCXX_USE_NOEXCEPT{
return m_msg.c_str();
}
protected:
std::string m_msg;
};
class CoapFrontend: public Frontend, public AvahiService,
public std::thread{
public:
......@@ -26,12 +47,107 @@ public:
virtual ~CoapFrontend();
protected:
uint16_t m_port;
static void s_get_index(coap_context_t *ctx,
struct coap_resource_t *resource,
const coap_endpoint_t *local_interface,
coap_address_t *peer,
coap_pdu_t *request,
str *token,
coap_pdu_t *response);
static void s_get_height(coap_context_t *ctx,
struct coap_resource_t *resource,
const coap_endpoint_t *local_interface,
coap_address_t *peer,
coap_pdu_t *request,
str *token,
coap_pdu_t *response);
static void s_put_height(coap_context_t *ctx,
struct coap_resource_t *resource,
const coap_endpoint_t *local_interface,
coap_address_t *peer,
coap_pdu_t *request,
str *token,
coap_pdu_t *response);
static void s_get_offset(coap_context_t *ctx,
struct coap_resource_t *resource,
const coap_endpoint_t *local_interface,
coap_address_t *peer,
coap_pdu_t *request,
str *token,
coap_pdu_t *response);
static void s_put_offset(coap_context_t *ctx,
struct coap_resource_t *resource,
const coap_endpoint_t *local_interface,
coap_address_t *peer,
coap_pdu_t *request,
str *token,
coap_pdu_t *response);
coap_context_t* get_context(const char *node, int port);
void init_resources(coap_context_t *ctx);
void hnd_get_index(coap_context_t *ctx,
struct coap_resource_t *resource,
const coap_endpoint_t *local_interface,
coap_address_t *peer,
coap_pdu_t *request,
str *token,
coap_pdu_t *response);
void hnd_get_height(coap_context_t *ctx,
struct coap_resource_t *resource,
const coap_endpoint_t *local_interface,
coap_address_t *peer,
coap_pdu_t *request,
str *token,
coap_pdu_t *response);
void hnd_put_height(coap_context_t *ctx,
struct coap_resource_t *resource,
const coap_endpoint_t *local_interface,
coap_address_t *peer,
coap_pdu_t *request,
str *token,
coap_pdu_t *response);
void hnd_get_offset(coap_context_t *ctx,
struct coap_resource_t *resource,
const coap_endpoint_t *local_interface,
coap_address_t *peer,
coap_pdu_t *request,
str *token,
coap_pdu_t *response);
void hnd_put_offset(coap_context_t *ctx,
struct coap_resource_t *resource,
const coap_endpoint_t *local_interface,
coap_address_t *peer,
coap_pdu_t *request,
str *token,
coap_pdu_t *response);
virtual void notify(DeskNotification& height);
void check_async(coap_context_t *ctx,
const coap_endpoint_t *local_if,
coap_tick_t now);
void run(void);