-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
ebcfa91
commit f6f03ac
Showing
6 changed files
with
533 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# name of your application | ||
APPLICATION = lf-test | ||
|
||
# If no BOARD is found in the environment, use this default: | ||
BOARD ?= native | ||
|
||
# Comment this out to disable code in RIOT that does safety checking | ||
# which is not needed in a production environment but helps in the | ||
# development process: | ||
DEVELHELP ?= 1 | ||
|
||
# Change this to 0 show compiler invocation lines by default: | ||
QUIET ?= 1 | ||
|
||
# Enable reactor-uc features | ||
# CFLAGS += -DNETWORK_CHANNEL_TCP_POSIX | ||
CFLAGS += -DNETWORK_CHANNEL_COAP_RIOT | ||
CFLAGS += -DEVENT_QUEUE_SIZE=32 | ||
CFLAGS += -DREACTION_QUEUE_SIZE=32 | ||
|
||
USEMODULE += shell_cmds_default | ||
USEMODULE += ps | ||
USEMODULE += shell | ||
USEMODULE += gnrc_icmpv6_echo | ||
USEMODULE += ipv4_addr | ||
USEMODULE += shell_cmd_gnrc_udp | ||
|
||
include $(CURDIR)/../../../make/riot/riot.mk |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,284 @@ | ||
#include "coap_channel.h" | ||
#include "reactor-uc/logging.h" | ||
#include "reactor-uc/environment.h" | ||
|
||
#include <stdbool.h> | ||
#include <stdint.h> | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
|
||
#include "net/gcoap.h" | ||
#include "net/ipv6/addr.h" | ||
#include "net/ipv4/addr.h" | ||
#include "net/sock/util.h" | ||
#include "od.h" | ||
#include "uri_parser.h" | ||
|
||
static bool _is_coap_initialized = false; | ||
static Environment *_env; | ||
|
||
static CoapChannel *_get_coap_channel_by_remote(sock_udp_ep_t *remote) { | ||
CoapChannel *channel; | ||
for (size_t i = 0; i < _env->net_bundles_size; i++) { | ||
channel = (CoapChannel *)_env->net_bundles[i]->net_channel; | ||
|
||
if (remote->family == AF_INET6) { | ||
if (ipv6_addr_equal(&channel->remote.addr.ipv6, &remote->addr.ipv6)) { | ||
return channel; | ||
} | ||
} else if (remote->family == AF_INET) { | ||
if (ipv4_addr_equal(&channel->remote.addr.ipv4, &remote->addr.ipv4)) { | ||
return channel; | ||
} | ||
} | ||
} | ||
|
||
return NULL; | ||
} | ||
|
||
// static void _resp_handler(const gcoap_request_memo_t *memo, coap_pkt_t *pdu, const sock_udp_ep_t *remote) { | ||
// (void)remote; /* not interested in the source currently */ | ||
|
||
// if (memo->state == GCOAP_MEMO_TIMEOUT) { | ||
// LF_DEBUG(NET, "gcoap: timeout for msg ID %02u\n", coap_get_id(pdu)); | ||
// return; | ||
// } | ||
|
||
// char *class_str = (coap_get_code_class(pdu) == COAP_CLASS_SUCCESS) ? "Success" : "Error"; | ||
// LF_DEBUG(NET, "gcoap: response %s, code %1u.%02u", class_str, coap_get_code_class(pdu), coap_get_code_detail(pdu)); | ||
// if (pdu->payload_len) { | ||
// unsigned content_type = coap_get_content_type(pdu); | ||
// if (content_type == COAP_FORMAT_TEXT || content_type == COAP_FORMAT_LINK || | ||
// coap_get_code_class(pdu) == COAP_CLASS_CLIENT_FAILURE || | ||
// coap_get_code_class(pdu) == COAP_CLASS_SERVER_FAILURE) { | ||
// /* Expecting diagnostic payload in failure cases */ | ||
// LF_DEBUG(NET, ", %u bytes\n%.*s\n", pdu->payload_len, pdu->payload_len, (char *)pdu->payload); | ||
// } else { | ||
// LF_DEBUG(NET, ", %u bytes\n", pdu->payload_len); | ||
// od_hex_dump(pdu->payload, pdu->payload_len, OD_WIDTH_DEFAULT); | ||
// } | ||
// } else { | ||
// LF_DEBUG(NET, ", empty payload\n"); | ||
// } | ||
// } | ||
|
||
static bool _send_coap_message(sock_udp_ep_t *remote, char *path, gcoap_resp_handler_t resp_handler) { | ||
coap_pkt_t pdu; | ||
uint8_t buf[CONFIG_GCOAP_PDU_BUF_SIZE]; | ||
unsigned msg_type = COAP_TYPE_NON; | ||
|
||
gcoap_req_init(&pdu, &buf[0], CONFIG_GCOAP_PDU_BUF_SIZE, msg_type, path); | ||
coap_hdr_set_type(pdu.hdr, msg_type); | ||
ssize_t len = coap_opt_finish(&pdu, COAP_OPT_FINISH_NONE); | ||
ssize_t bytes_sent = gcoap_req_send(buf, len, remote, NULL, resp_handler, NULL, GCOAP_SOCKET_TYPE_UDP); | ||
LF_DEBUG(NET, "CoapChannel: %d", bytes_sent); | ||
if (bytes_sent > 0) { | ||
LF_DEBUG(NET, "CoapChannel: Successfully sent"); | ||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
static ssize_t _server_connect_handler(coap_pkt_t *pdu, uint8_t *buf, size_t len, coap_request_ctx_t *ctx) { | ||
LF_DEBUG(NET, "CoapChannel: Server connect handler"); | ||
CoapChannel *self = _get_coap_channel_by_remote(ctx->remote); | ||
(void)self; | ||
|
||
// TODO: If state not open or already connected, then: return bool with FALSE and also handle this bool in client | ||
// TODO: Also: if self is NULL, then there is no channel that this federate supports for the other federate => return | ||
// false as well. | ||
|
||
// 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); | ||
|
||
// if (self->connected_to_client) { | ||
// // This server is already connected to a client | ||
// return false; | ||
// } | ||
|
||
// // Set as connected | ||
// self->connected_to_client = true; | ||
|
||
// // Connect successful | ||
// return true; | ||
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 ssize_t _server_disconnect_handler(coap_pkt_t *pdu, uint8_t *buf, size_t len, coap_request_ctx_t *ctx) { | ||
LF_DEBUG(NET, "CoapChannel: Server disconnect handler"); | ||
CoapChannel *self = _get_coap_channel_by_remote(ctx->remote); | ||
|
||
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); | ||
|
||
// Set as disconnect | ||
self->state = NETWORK_CHANNEL_STATE_DISCONNECTED; | ||
|
||
// Disconnect successful | ||
return true; | ||
} | ||
|
||
static ssize_t _server_message_handler(coap_pkt_t *pdu, uint8_t *buf, size_t len, coap_request_ctx_t *ctx) { | ||
LF_DEBUG(NET, "CoapChannel: Server message handler"); | ||
CoapChannel *self = _get_coap_channel_by_remote(ctx->remote); | ||
|
||
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); | ||
|
||
// TODO | ||
|
||
return true; | ||
} | ||
|
||
static const coap_resource_t _resources[] = { | ||
{"/connect", COAP_GET, _server_connect_handler, NULL}, | ||
{"/disconnect", COAP_GET, _server_disconnect_handler, NULL}, | ||
{"/message", COAP_GET, _server_message_handler, NULL}, | ||
}; | ||
|
||
static gcoap_listener_t _listener = {&_resources[0], ARRAY_SIZE(_resources), GCOAP_SOCKET_TYPE_UDP, NULL, NULL, NULL}; | ||
|
||
static lf_ret_t CoapChannel_open_connection(NetworkChannel *untyped_self) { | ||
LF_DEBUG(NET, "CoapChannel: Open connection"); | ||
CoapChannel *self = (CoapChannel *)untyped_self; | ||
|
||
/* Server */ | ||
// Do nothing | ||
|
||
/* Client */ | ||
// Do nothing | ||
|
||
self->state = NETWORK_CHANNEL_STATE_OPEN; | ||
} | ||
|
||
static void _client_try_connect_callback(const gcoap_request_memo_t *memo, coap_pkt_t *pdu, | ||
const sock_udp_ep_t *remote) { | ||
LF_DEBUG(NET, "CoapChannel: Try connect callback"); | ||
CoapChannel *self = _get_coap_channel_by_remote(remote); | ||
|
||
if (memo->state == GCOAP_MEMO_TIMEOUT || coap_get_code_class(pdu) != COAP_CLASS_SUCCESS) { | ||
self->state = NETWORK_CHANNEL_STATE_DISCONNECTED; | ||
return; | ||
} | ||
|
||
// TODO: Analyse payload. The remote federate might respond with "false" it it is not open for connections or if it is | ||
// already connected | ||
|
||
self->state = NETWORK_CHANNEL_STATE_CONNECTED; | ||
} | ||
|
||
static lf_ret_t CoapChannel_try_connect(NetworkChannel *untyped_self) { | ||
LF_DEBUG(NET, "CoapChannel: Try connect"); | ||
CoapChannel *self = (CoapChannel *)untyped_self; | ||
|
||
/* Server */ | ||
// Do nothing. Every CoAP client is also a server in our case. | ||
// If the client successfully connected to the server of the other federate, | ||
// then we consider the connection as established | ||
// The other federate will also connect to our server and after that consider | ||
// the connection to us as established. | ||
|
||
/* Client */ | ||
switch (self->state) { | ||
case NETWORK_CHANNEL_STATE_CONNECTED: | ||
return LF_OK; | ||
|
||
case NETWORK_CHANNEL_STATE_OPEN: | ||
if (!_send_coap_message(&self->remote, "/connect", _client_try_connect_callback)) { | ||
LF_ERR(NET, "CoapChannel: try_connect: Failed to send CoAP message"); | ||
return LF_ERR; | ||
} | ||
return LF_IN_PROGRESS; | ||
|
||
case NETWORK_CHANNEL_STATE_CONNECTION_IN_PROGRESS: | ||
return LF_IN_PROGRESS; | ||
|
||
case NETWORK_CHANNEL_STATE_DISCONNECTED: | ||
case NETWORK_CHANNEL_STATE_LOST_CONNECTION: | ||
self->state = NETWORK_CHANNEL_STATE_OPEN; | ||
return LF_TRY_AGAIN; | ||
|
||
case NETWORK_CHANNEL_STATE_UNINITIALIZED: | ||
return LF_ERR; | ||
} | ||
} | ||
|
||
static void CoapChannel_close_connection(NetworkChannel *untyped_self) { | ||
LF_DEBUG(NET, "CoapChannel: Close connection"); | ||
CoapChannel *self = (CoapChannel *)untyped_self; | ||
|
||
// TODO | ||
} | ||
|
||
static lf_ret_t CoapChannel_send_blocking(NetworkChannel *untyped_self, const FederateMessage *message) { | ||
LF_DEBUG(NET, "CoapChannel: Send blocking"); | ||
CoapChannel *self = (CoapChannel *)untyped_self; | ||
|
||
// TODO | ||
} | ||
|
||
static void CoapChannel_register_receive_callback(NetworkChannel *untyped_self, | ||
void (*receive_callback)(FederatedConnectionBundle *conn, | ||
const FederateMessage *msg), | ||
FederatedConnectionBundle *conn) { | ||
LF_INFO(NET, "CoapChannel: Register receive callback"); | ||
CoapChannel *self = (CoapChannel *)untyped_self; | ||
|
||
self->receive_callback = receive_callback; | ||
self->federated_connection = conn; | ||
} | ||
|
||
static void CoapChannel_free(NetworkChannel *untyped_self) { | ||
LF_DEBUG(NET, "CoapChannel: Free"); | ||
CoapChannel *self = (CoapChannel *)untyped_self; | ||
|
||
// TODO | ||
} | ||
|
||
void CoapChannel_ctor(CoapChannel *self, Environment *env, const char *remote_host) { | ||
// Initialize global coap server it not already done | ||
if (!_is_coap_initialized) { | ||
_is_coap_initialized = true; | ||
|
||
// Set environment | ||
_env = env; | ||
|
||
// Initialize coap server | ||
gcoap_register_listener(&_listener); | ||
} | ||
|
||
// Super fields | ||
self->super.open_connection = CoapChannel_open_connection; | ||
self->super.try_connect = CoapChannel_try_connect; | ||
self->super.close_connection = CoapChannel_close_connection; | ||
self->super.send_blocking = CoapChannel_send_blocking; | ||
self->super.register_receive_callback = CoapChannel_register_receive_callback; | ||
self->super.free = CoapChannel_free; | ||
|
||
// Concrete fields | ||
self->receive_callback = NULL; | ||
self->federated_connection = NULL; | ||
self->state = NETWORK_CHANNEL_STATE_UNINITIALIZED; | ||
|
||
// Convert host to udp socket | ||
sock_udp_name2ep(&self->remote, remote_host); | ||
if (self->remote.port == 0) { | ||
self->remote.port = CONFIG_GCOAP_PORT; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
#ifndef REACTOR_UC_COAP_CHANNEL_H | ||
#define REACTOR_UC_COAP_CHANNEL_H | ||
#include "reactor-uc/network_channel.h" | ||
#include "reactor-uc/environment.h" | ||
#include "net/sock/udp.h" | ||
|
||
// #define COAP_CHANNEL_BUFFERSIZE 1024 | ||
// #define COAP_CHANNEL_NUM_RETRIES 255; | ||
// #define COAP_CHANNEL_RECV_THREAD_STACK_SIZE 2048 | ||
// #define COAP_CHANNEL_RECV_THREAD_STACK_GUARD_SIZE 128 | ||
|
||
typedef enum { | ||
SERVER_COAP_CHANNEL, | ||
CLIENT_COAP_CHANNEL, | ||
} CoapChannelType; | ||
|
||
typedef struct CoapChannel CoapChannel; | ||
typedef struct FederatedConnectionBundle FederatedConnectionBundle; | ||
|
||
struct CoapChannel { | ||
NetworkChannel super; | ||
|
||
sock_udp_ep_t remote; | ||
|
||
NetworkChannelState state; | ||
|
||
FederatedConnectionBundle *federated_connection; | ||
void (*receive_callback)(FederatedConnectionBundle *conn, const FederateMessage *message); | ||
}; | ||
|
||
void CoapChannel_ctor(CoapChannel *self, Environment *env, const char *remote_host); | ||
|
||
#endif |
Oops, something went wrong.