mirror of
https://github.com/servalproject/serval-dna.git
synced 2024-12-18 20:57:56 +00:00
Send a meshmb message via restful api
This commit is contained in:
parent
7f6316b7df
commit
c2956568d6
@ -268,6 +268,7 @@ ATOM(bool_t, rhizome_direct, 0, boolean,, "")
|
||||
ATOM(bool_t, server, 0, boolean,, "")
|
||||
ATOM(bool_t, subscriber, 0, boolean,, "")
|
||||
ATOM(bool_t, meshms, 0, boolean,, "")
|
||||
ATOM(bool_t, meshmb, 0, boolean,, "")
|
||||
ATOM(bool_t, vomp, 0, boolean,, "")
|
||||
ATOM(bool_t, profiling, 0, boolean,, "")
|
||||
ATOM(bool_t, linkstate, 0, boolean,, "")
|
||||
|
@ -122,10 +122,11 @@ int str_to_identity_t(identity_t *idp, const char *hex)
|
||||
return parse_hex_t(idp, hex);
|
||||
}
|
||||
|
||||
int strn_to_identity_t(identity_t *idp, const char *hex, size_t hexlen)
|
||||
int strn_to_identity_t(identity_t *idp, const char *hex, const char **endp)
|
||||
{
|
||||
const char *endp;
|
||||
return parse_hexn_t(idp, hex, hexlen, &endp);
|
||||
if (strn_fromhex(idp->binary, sizeof *idp, hex, endp)==sizeof *idp)
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
@ -13,6 +13,7 @@ HDRS= fifo.h \
|
||||
httpd.h \
|
||||
instance.h \
|
||||
meshms.h \
|
||||
meshmb.h \
|
||||
message_ply.h \
|
||||
nibble_tree.h \
|
||||
serval_types.h \
|
||||
|
2
httpd.h
2
httpd.h
@ -176,7 +176,7 @@ typedef struct httpd_request
|
||||
/* For responses that list MeshMS messages in a single conversation.
|
||||
*/
|
||||
struct {
|
||||
struct newsince_position {
|
||||
struct meshms_position {
|
||||
enum meshms_which_ply which_ply;
|
||||
uint64_t offset;
|
||||
uint64_t their_ack;
|
||||
|
12
meshmb.c
12
meshmb.c
@ -1,3 +1,4 @@
|
||||
#include "serval.h"
|
||||
#include "serval_types.h"
|
||||
#include "dataformats.h"
|
||||
#include "cli.h"
|
||||
@ -8,7 +9,7 @@
|
||||
#include "commandline.h"
|
||||
#include "overlay_buffer.h"
|
||||
|
||||
static int meshmb_send(keyring_identity *id, const char *message, size_t message_len,
|
||||
int meshmb_send(keyring_identity *id, const char *message, size_t message_len,
|
||||
unsigned nassignments, const struct rhizome_manifest_field_assignment *assignments){
|
||||
|
||||
struct message_ply ply;
|
||||
@ -43,8 +44,8 @@ static int app_meshmb_send(const struct cli_parsed *parsed, struct cli_context *
|
||||
|
||||
unsigned nfields = (parsed->varargi == -1) ? 0 : parsed->argc - (unsigned)parsed->varargi;
|
||||
struct rhizome_manifest_field_assignment fields[nfields];
|
||||
if (nfields) {
|
||||
assert(parsed->varargi >= 0);
|
||||
|
||||
if (nfields){
|
||||
if (rhizome_parse_field_assignments(fields, nfields, parsed->args + parsed->varargi)==-1)
|
||||
return -1;
|
||||
}
|
||||
@ -55,13 +56,12 @@ static int app_meshmb_send(const struct cli_parsed *parsed, struct cli_context *
|
||||
|
||||
if (create_serval_instance_dir() == -1)
|
||||
return -1;
|
||||
if (rhizome_opendb() == -1)
|
||||
return -1;
|
||||
if (!(keyring = keyring_open_instance_cli(parsed)))
|
||||
return -1;
|
||||
|
||||
int ret = -1;
|
||||
if (rhizome_opendb() == -1)
|
||||
goto end;
|
||||
|
||||
keyring_identity *id = keyring_find_identity(keyring, &identity);
|
||||
if (!id){
|
||||
WHY("Invalid identity");
|
||||
|
7
meshmb.h
Normal file
7
meshmb.h
Normal file
@ -0,0 +1,7 @@
|
||||
#ifndef __SERVAL_DNA__MESHMB_H
|
||||
#define __SERVAL_DNA__MESHMB_H
|
||||
|
||||
int meshmb_send(keyring_identity *id, const char *message, size_t message_len,
|
||||
unsigned nassignments, const struct rhizome_manifest_field_assignment *assignments);
|
||||
|
||||
#endif
|
142
meshmb_restful.c
Normal file
142
meshmb_restful.c
Normal file
@ -0,0 +1,142 @@
|
||||
#include "serval.h"
|
||||
#include "conf.h"
|
||||
#include "httpd.h"
|
||||
#include "str.h"
|
||||
#include "numeric_str.h"
|
||||
#include "base64.h"
|
||||
#include "strbuf_helpers.h"
|
||||
#include "meshmb.h"
|
||||
|
||||
DEFINE_FEATURE(http_rest_meshmb);
|
||||
|
||||
static char *PART_MESSAGE = "message";
|
||||
static int send_part_start(struct http_request *hr)
|
||||
{
|
||||
httpd_request *r = (httpd_request *) hr;
|
||||
assert(r->u.sendmsg.current_part == NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int send_part_end(struct http_request *hr)
|
||||
{
|
||||
httpd_request *r = (httpd_request *) hr;
|
||||
if (r->u.sendmsg.current_part == PART_MESSAGE) {
|
||||
if (r->u.sendmsg.message.length == 0)
|
||||
return http_response_form_part(r, 400, "Invalid (empty)", PART_MESSAGE, NULL, 0);
|
||||
r->u.sendmsg.received_message = 1;
|
||||
DEBUGF(httpd, "received %s = %s", PART_MESSAGE, alloca_toprint(-1, r->u.sendmsg.message.buffer, r->u.sendmsg.message.length));
|
||||
} else
|
||||
FATALF("current_part = %s", alloca_str_toprint(r->u.sendmsg.current_part));
|
||||
r->u.sendmsg.current_part = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int send_part_header(struct http_request *hr, const struct mime_part_headers *h)
|
||||
{
|
||||
httpd_request *r = (httpd_request *) hr;
|
||||
if (!h->content_disposition.type[0])
|
||||
return http_response_content_disposition(r, 415, "Missing", h->content_disposition.type);
|
||||
if (strcmp(h->content_disposition.type, "form-data") != 0)
|
||||
return http_response_content_disposition(r, 415, "Unsupported", h->content_disposition.type);
|
||||
if (strcmp(h->content_disposition.name, PART_MESSAGE) == 0) {
|
||||
if (r->u.sendmsg.received_message)
|
||||
return http_response_form_part(r, 400, "Duplicate", PART_MESSAGE, NULL, 0);
|
||||
r->u.sendmsg.current_part = PART_MESSAGE;
|
||||
form_buf_malloc_init(&r->u.sendmsg.message, MESSAGE_PLY_MAX_LEN);
|
||||
}
|
||||
else
|
||||
return http_response_form_part(r, 415, "Unsupported", h->content_disposition.name, NULL, 0);
|
||||
if (!h->content_type.type[0] || !h->content_type.subtype[0])
|
||||
return http_response_content_type(r, 400, "Missing", &h->content_type);
|
||||
if (strcmp(h->content_type.type, "text") != 0 || strcmp(h->content_type.subtype, "plain") != 0)
|
||||
return http_response_content_type(r, 415, "Unsupported", &h->content_type);
|
||||
if (!h->content_type.charset[0])
|
||||
return http_response_content_type(r, 400, "Missing charset", &h->content_type);
|
||||
if (strcmp(h->content_type.charset, "utf-8") != 0)
|
||||
return http_response_content_type(r, 415, "Unsupported charset", &h->content_type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int send_part_body(struct http_request *hr, char *buf, size_t len)
|
||||
{
|
||||
httpd_request *r = (httpd_request *) hr;
|
||||
if (r->u.sendmsg.current_part == PART_MESSAGE) {
|
||||
form_buf_malloc_accumulate(r, PART_MESSAGE, &r->u.sendmsg.message, buf, len);
|
||||
} else
|
||||
FATALF("current_part = %s", alloca_str_toprint(r->u.sendmsg.current_part));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int send_content_end(struct http_request *hr)
|
||||
{
|
||||
httpd_request *r = (httpd_request *) hr;
|
||||
if (!r->u.sendmsg.received_message)
|
||||
return http_response_form_part(r, 400, "Missing", PART_MESSAGE, NULL, 0);
|
||||
assert(r->u.sendmsg.message.length > 0);
|
||||
assert(r->u.sendmsg.message.length <= MESSAGE_PLY_MAX_LEN);
|
||||
|
||||
keyring_identity *id = keyring_find_identity(keyring, &r->bid);
|
||||
if (!id){
|
||||
http_request_simple_response(&r->http, 500, "TODO, detailed errors");
|
||||
return 500;
|
||||
}
|
||||
if (meshmb_send(id, r->u.sendmsg.message.buffer, r->u.sendmsg.message.length, 0, NULL)==-1){
|
||||
http_request_simple_response(&r->http, 500, "TODO, detailed errors");
|
||||
return 500;
|
||||
}
|
||||
http_request_simple_response(&r->http, 201, "TODO, detailed response");
|
||||
return 201;
|
||||
}
|
||||
|
||||
static void send_finalise(httpd_request *r)
|
||||
{
|
||||
form_buf_malloc_release(&r->u.sendmsg.message);
|
||||
}
|
||||
|
||||
static int restful_meshmb_send(httpd_request *r, const char *remainder)
|
||||
{
|
||||
if (*remainder)
|
||||
return 404;
|
||||
assert(r->finalise_union == NULL);
|
||||
r->finalise_union = send_finalise;
|
||||
// Parse the request body as multipart/form-data.
|
||||
assert(r->u.sendmsg.current_part == NULL);
|
||||
assert(!r->u.sendmsg.received_message);
|
||||
r->http.form_data.handle_mime_part_start = send_part_start;
|
||||
r->http.form_data.handle_mime_part_end = send_part_end;
|
||||
r->http.form_data.handle_mime_part_header = send_part_header;
|
||||
r->http.form_data.handle_mime_body = send_part_body;
|
||||
// Send the message once the body has arrived.
|
||||
r->http.handle_content_end = send_content_end;
|
||||
return 1;
|
||||
}
|
||||
|
||||
DECLARE_HANDLER("/restful/meshmb/", restful_meshmb_);
|
||||
static int restful_meshmb_(httpd_request *r, const char *remainder)
|
||||
{
|
||||
r->http.response.header.content_type = CONTENT_TYPE_JSON;
|
||||
if (!is_rhizome_http_enabled())
|
||||
return 404;
|
||||
int ret = authorize_restful(&r->http);
|
||||
if (ret)
|
||||
return ret;
|
||||
const char *verb = HTTP_VERB_GET;
|
||||
HTTP_HANDLER *handler = NULL;
|
||||
const char *end;
|
||||
|
||||
if (strn_to_identity_t(&r->bid, remainder, &end) != -1) {
|
||||
remainder = end;
|
||||
|
||||
if (strcmp(remainder, "/sendmessage") == 0) {
|
||||
handler = restful_meshmb_send;
|
||||
verb = HTTP_VERB_POST;
|
||||
remainder = "";
|
||||
}
|
||||
}
|
||||
|
||||
if (handler == NULL)
|
||||
return 404;
|
||||
if (r->http.verb != verb)
|
||||
return 405;
|
||||
return handler(r, remainder);
|
||||
}
|
@ -51,7 +51,7 @@ static void finalise_union_meshms_sendmessage(httpd_request *r)
|
||||
#define MESHMS_TOKEN_STRLEN (BASE64_ENCODED_LEN(MAX_TOKEN_LEN))
|
||||
#define alloca_meshms_token(pos) meshms_token_to_str(alloca(MESHMS_TOKEN_STRLEN + 1), (pos))
|
||||
|
||||
static char *meshms_token_to_str(char *buf, struct newsince_position *pos)
|
||||
static char *meshms_token_to_str(char *buf, struct meshms_position *pos)
|
||||
{
|
||||
uint8_t tmp[MAX_TOKEN_LEN];
|
||||
int ofs = 0;
|
||||
@ -65,7 +65,7 @@ static char *meshms_token_to_str(char *buf, struct newsince_position *pos)
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int strn_to_meshms_token(const char *str, struct newsince_position *pos, const char **afterp)
|
||||
static int strn_to_meshms_token(const char *str, struct meshms_position *pos, const char **afterp)
|
||||
{
|
||||
uint8_t token[MAX_TOKEN_LEN];
|
||||
size_t token_len = base64url_decode(token, sizeof token, str, 0, afterp, 0, NULL);
|
||||
|
@ -92,8 +92,8 @@ int sid_get_special_type(const sid_t *sid);
|
||||
#define alloca_tohex_identity_t(identity) alloca_tohex((identity)->binary, IDENTITY_SIZE)
|
||||
|
||||
int cmp_identity_t(const identity_t *a, const identity_t *b);
|
||||
int str_to_identity_t(identity_t *sid, const char *hex);
|
||||
int strn_to_identity_t(identity_t *sid, const char *hex, size_t hexlen);
|
||||
int str_to_identity_t(identity_t *id, const char *hex);
|
||||
int strn_to_identity_t(identity_t *idp, const char *hex, const char **endp);
|
||||
|
||||
/* MDP port number
|
||||
*/
|
||||
|
@ -57,6 +57,7 @@ void servald_features()
|
||||
USE_FEATURE(http_rest_keyring);
|
||||
USE_FEATURE(http_rest_rhizome);
|
||||
USE_FEATURE(http_rest_meshms);
|
||||
USE_FEATURE(http_rest_meshmb);
|
||||
}
|
||||
|
||||
#include <assert.h>
|
||||
|
@ -67,6 +67,7 @@ SERVAL_DAEMON_SOURCES = \
|
||||
message_ply.c \
|
||||
meshms_cli.c \
|
||||
meshms_restful.c \
|
||||
meshmb_restful.c \
|
||||
msp_client.c \
|
||||
msp_proxy.c \
|
||||
monitor.c \
|
||||
|
66
tests/meshmbrestful
Executable file
66
tests/meshmbrestful
Executable file
@ -0,0 +1,66 @@
|
||||
#!/bin/bash
|
||||
|
||||
source "${0%/*}/../testframework.sh"
|
||||
source "${0%/*}/../testdefs.sh"
|
||||
source "${0%/*}/../testdefs_json.sh"
|
||||
|
||||
setup_instance() {
|
||||
set_instance $1
|
||||
executeOk_servald config \
|
||||
set api.restful.users.harry.password potter \
|
||||
set api.restful.users.ron.password weasley \
|
||||
set api.restful.users.hermione.password grainger \
|
||||
set debug.http_server on \
|
||||
set debug.httpd on \
|
||||
set debug.meshmb on \
|
||||
set debug.verbose on \
|
||||
set log.console.level debug
|
||||
set_extra_config
|
||||
if [ -z "$IDENTITY_COUNT" ]; then
|
||||
create_single_identity
|
||||
else
|
||||
create_identities $IDENTITY_COUNT
|
||||
fi
|
||||
}
|
||||
|
||||
set_extra_config() {
|
||||
:
|
||||
}
|
||||
|
||||
setup() {
|
||||
setup_curl 7
|
||||
setup_json
|
||||
setup_servald
|
||||
export SERVALD_RHIZOME_DB_RETRY_LIMIT_MS=60000
|
||||
setup_instance +A
|
||||
start_servald_instances +A
|
||||
wait_until servald_restful_http_server_started +A
|
||||
get_servald_restful_http_server_port PORTA +A
|
||||
}
|
||||
|
||||
finally() {
|
||||
stop_all_servald_servers
|
||||
}
|
||||
|
||||
teardown() {
|
||||
kill_all_servald_processes
|
||||
assert_no_servald_processes
|
||||
report_all_servald_servers
|
||||
}
|
||||
|
||||
doc_MeshmbSend="Send a broadcast message"
|
||||
test_MeshmbSend() {
|
||||
executeOk curl \
|
||||
-H "Expect:" \
|
||||
--silent --fail --show-error \
|
||||
--output sendmessage.json \
|
||||
--basic --user harry:potter \
|
||||
--form "message=Hello World;type=text/plain;charset=utf-8" \
|
||||
"http://$addr_localhost:$PORTA/restful/meshmb/$IDA1/sendmessage"
|
||||
executeOk_servald rhizome export bundle $IDA1 broadcast.manifest broadcast
|
||||
tfw_cat -h broadcast.manifest
|
||||
tfw_cat -h broadcast
|
||||
}
|
||||
|
||||
runTests "$@"
|
||||
|
Loading…
Reference in New Issue
Block a user