2014-01-22 06:11:22 +00:00
|
|
|
/*
|
|
|
|
Serval DNA MeshMS
|
|
|
|
Copyright (C) 2014 Serval Project Inc.
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public License
|
|
|
|
as published by the Free Software Foundation; either version 2
|
|
|
|
of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef __SERVAL_DNA__MESHMS_H
|
|
|
|
#define __SERVAL_DNA__MESHMS_H
|
|
|
|
|
2017-11-24 00:03:39 +00:00
|
|
|
#include <stdint.h>
|
|
|
|
|
2014-02-06 07:07:35 +00:00
|
|
|
#ifndef __MESHMS_INLINE
|
|
|
|
# if __GNUC__ && !__GNUC_STDC_INLINE__
|
|
|
|
# define __MESHMS_INLINE extern inline
|
|
|
|
# else
|
|
|
|
# define __MESHMS_INLINE inline
|
|
|
|
# endif
|
|
|
|
#endif
|
|
|
|
|
2014-01-22 06:11:22 +00:00
|
|
|
#include "rhizome.h"
|
2016-06-28 03:39:02 +00:00
|
|
|
#include "message_ply.h"
|
2014-02-05 03:58:15 +00:00
|
|
|
|
2014-02-06 07:07:35 +00:00
|
|
|
/* The result of a MeshMS operation. Negative indicates failure, zero or
|
|
|
|
* positive success.
|
|
|
|
*/
|
|
|
|
enum meshms_status {
|
|
|
|
MESHMS_STATUS_ERROR = -1, // unexpected error (underlying failure)
|
|
|
|
MESHMS_STATUS_OK = 0, // operation succeeded, no bundle changed
|
|
|
|
MESHMS_STATUS_UPDATED = 1, // operation succeeded, bundle updated
|
|
|
|
MESHMS_STATUS_SID_LOCKED = 2, // cannot decode or send messages for that SID
|
2014-02-07 05:58:40 +00:00
|
|
|
MESHMS_STATUS_PROTOCOL_FAULT = 3, // missing or faulty ply bundle
|
2014-02-06 07:07:35 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
__MESHMS_INLINE int meshms_failed(enum meshms_status status) {
|
|
|
|
return status != MESHMS_STATUS_OK && status != MESHMS_STATUS_UPDATED;
|
|
|
|
}
|
|
|
|
|
2014-07-04 02:38:49 +00:00
|
|
|
const char *meshms_status_message(enum meshms_status);
|
|
|
|
|
2016-08-17 01:58:36 +00:00
|
|
|
struct meshms_metadata{
|
|
|
|
// what is the offset of their last message
|
|
|
|
uint64_t their_last_message;
|
|
|
|
// what is the offset of their last ack
|
|
|
|
uint64_t their_last_ack_offset;
|
|
|
|
// where in our ply, does their ack point
|
|
|
|
uint64_t their_last_ack;
|
|
|
|
// what is the last message we marked as read
|
|
|
|
uint64_t read_offset;
|
|
|
|
// our cached value for the last known size of their ply
|
|
|
|
uint64_t their_size;
|
|
|
|
|
|
|
|
// where in their ply, does our last ack point
|
|
|
|
uint64_t my_last_ack;
|
|
|
|
// our cached value for the last known size of our ply
|
|
|
|
uint64_t my_size;
|
|
|
|
};
|
|
|
|
|
2014-01-22 06:11:22 +00:00
|
|
|
struct meshms_conversations {
|
2014-10-27 00:38:02 +00:00
|
|
|
struct meshms_conversations *_next;
|
2014-01-22 06:11:22 +00:00
|
|
|
|
|
|
|
// who are we talking to?
|
|
|
|
sid_t them;
|
|
|
|
|
2016-06-28 03:39:02 +00:00
|
|
|
struct message_ply my_ply;
|
|
|
|
struct message_ply their_ply;
|
2016-08-17 01:58:36 +00:00
|
|
|
|
|
|
|
struct meshms_metadata metadata;
|
2014-01-22 06:11:22 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* Fetch the list of all MeshMS conversations into a binary tree whose nodes
|
|
|
|
* are all allocated by malloc(3).
|
|
|
|
*/
|
2016-08-17 01:58:36 +00:00
|
|
|
enum meshms_status meshms_conversations_list(const struct keyring_identity *id, const sid_t *my_sid, struct meshms_conversations **conv);
|
2014-01-22 06:11:22 +00:00
|
|
|
void meshms_free_conversations(struct meshms_conversations *conv);
|
|
|
|
|
|
|
|
/* For iterating over a binary tree of all MeshMS conversations, as created by
|
|
|
|
* meshms_conversations_list().
|
2014-01-24 01:11:31 +00:00
|
|
|
*
|
|
|
|
* struct meshms_conversation_iterator it;
|
|
|
|
* meshms_conversation_iterator_start(&it, conv);
|
|
|
|
* while (it.current) {
|
|
|
|
* ...
|
|
|
|
* meshms_conversation_iterator_advance(&it);
|
|
|
|
* }
|
2014-01-22 06:11:22 +00:00
|
|
|
*/
|
|
|
|
struct meshms_conversation_iterator {
|
|
|
|
struct meshms_conversations *current;
|
|
|
|
};
|
|
|
|
void meshms_conversation_iterator_start(struct meshms_conversation_iterator *, struct meshms_conversations *);
|
|
|
|
void meshms_conversation_iterator_advance(struct meshms_conversation_iterator *);
|
|
|
|
|
2014-01-24 01:11:31 +00:00
|
|
|
/* For iterating through the messages in a single MeshMS conversation; both
|
2014-02-06 07:07:35 +00:00
|
|
|
* plys threaded (interleaved) in the order as seen by the sender. The
|
|
|
|
* meshms_message_iterator_prev() function returns MESHMS_STATUS_UPDATED if it
|
|
|
|
* advances the iterator to a message, or MESHMS_STATUS_OK if there are no more
|
|
|
|
* messages. Any other return value indicates failure.
|
2014-01-24 01:11:31 +00:00
|
|
|
*
|
|
|
|
* struct meshms_message_iterator it;
|
2014-02-06 07:07:35 +00:00
|
|
|
* enum meshms_status status;
|
|
|
|
* if (meshms_failed(status = meshms_message_iterator_open(&it, &sender_sid, &recip_sid)))
|
2014-01-24 01:11:31 +00:00
|
|
|
* return -1;
|
2014-02-06 07:07:35 +00:00
|
|
|
* while ((status = meshms_message_iterator_prev(&it)) == MESHMS_STATUS_UPDATED) {
|
2014-01-24 01:11:31 +00:00
|
|
|
* ...
|
|
|
|
* }
|
|
|
|
* meshms_message_iterator_close(&it);
|
2014-02-06 07:07:35 +00:00
|
|
|
* if (meshms_failed(status))
|
2014-01-24 01:11:31 +00:00
|
|
|
* return -1;
|
|
|
|
* ...
|
|
|
|
*/
|
|
|
|
struct meshms_message_iterator {
|
2014-01-29 05:00:31 +00:00
|
|
|
// Public fields that remain fixed for the life of the iterator:
|
2016-05-31 03:20:32 +00:00
|
|
|
struct keyring_identity *identity;
|
2016-08-17 01:58:36 +00:00
|
|
|
sid_t my_sid;
|
|
|
|
sid_t their_sid;
|
|
|
|
|
|
|
|
struct message_ply my_ply;
|
|
|
|
struct message_ply their_ply;
|
|
|
|
|
|
|
|
struct meshms_metadata metadata;
|
|
|
|
|
2014-01-29 05:00:31 +00:00
|
|
|
// The following public fields change per message:
|
2014-11-11 06:41:43 +00:00
|
|
|
enum meshms_which_ply { NEITHER_PLY, MY_PLY, THEIR_PLY } which_ply;
|
2014-01-29 05:00:31 +00:00
|
|
|
enum { MESSAGE_SENT, MESSAGE_RECEIVED, ACK_RECEIVED } type;
|
|
|
|
// For MESSAGE_SENT 'offset' is the byte position within the local ply
|
|
|
|
// (mine). For MESSAGE_RECEIVED and ACK_RECEIVED, it is the byte position
|
|
|
|
// within the remote ply (theirs).
|
2014-07-14 01:59:49 +00:00
|
|
|
time_s_t timestamp;
|
2016-10-26 06:33:14 +00:00
|
|
|
uint64_t my_offset;
|
|
|
|
uint64_t their_offset; // 0 for records from MY_PLY
|
2014-02-05 03:58:15 +00:00
|
|
|
const char *text; // text of UTF8 message (NUL terminated)
|
|
|
|
size_t text_length; // excluding terminating NUL
|
2014-01-24 01:11:31 +00:00
|
|
|
union {
|
2014-01-29 05:00:31 +00:00
|
|
|
bool_t delivered; // for MESSAGE_SENT
|
|
|
|
bool_t read; // for MESSAGE_RECEIVED
|
|
|
|
uint64_t ack_offset; // for ACK_RECEIVED
|
2014-01-24 01:11:31 +00:00
|
|
|
};
|
|
|
|
// Private implementation -- could change, so don't use them.
|
2016-06-28 03:39:02 +00:00
|
|
|
struct message_ply_read _my_reader;
|
|
|
|
struct message_ply_read _their_reader;
|
2014-01-24 01:11:31 +00:00
|
|
|
uint64_t _end_range;
|
2016-08-17 01:58:36 +00:00
|
|
|
uint8_t _in_ack:1;
|
2014-01-24 01:11:31 +00:00
|
|
|
};
|
2014-02-06 07:07:35 +00:00
|
|
|
enum meshms_status meshms_message_iterator_open(struct meshms_message_iterator *, const sid_t *me, const sid_t *them);
|
2014-01-24 01:11:31 +00:00
|
|
|
void meshms_message_iterator_close(struct meshms_message_iterator *);
|
2014-02-06 07:07:35 +00:00
|
|
|
enum meshms_status meshms_message_iterator_prev(struct meshms_message_iterator *);
|
2014-01-24 01:11:31 +00:00
|
|
|
|
2014-02-05 03:58:15 +00:00
|
|
|
/* Append a message ('message_len' bytes of UTF8 at 'message') to the sender's
|
|
|
|
* ply in the conversation between 'sender' and 'recipient'. If no
|
2014-06-24 02:41:58 +00:00
|
|
|
* conversation (ply bundle) exists, then create it. Returns
|
|
|
|
* MESHMS_STATUS_UPDATED on success, any other value indicates a failure or
|
|
|
|
* error (which is already logged).
|
2014-02-05 03:58:15 +00:00
|
|
|
*/
|
2016-08-17 01:58:36 +00:00
|
|
|
|
2014-02-06 07:07:35 +00:00
|
|
|
enum meshms_status meshms_send_message(const sid_t *sender, const sid_t *recipient, const char *message, size_t message_len);
|
2014-02-05 03:58:15 +00:00
|
|
|
|
2014-06-24 02:41:58 +00:00
|
|
|
/* Update the read offset for one or more conversations. Returns
|
|
|
|
* MESHMS_STATUS_UPDATED on success, any other value indicates a failure or
|
|
|
|
* error (which is already logged).
|
|
|
|
*
|
|
|
|
* If 'offset' is greater than a conversation's last-received offset, then it
|
|
|
|
* is clamped to the last-received offset. This means that passing an offset
|
|
|
|
* of UINT64_MAX will mark the conversation as fully read, and an offset of
|
|
|
|
* zero will have no effect.
|
|
|
|
*
|
|
|
|
* If 'recipient' is NULL then all of the sender's conversations are marked
|
|
|
|
* with the given read offset. In this case it only makes sense to pass an
|
|
|
|
* offest of UINT64_MAX.
|
|
|
|
*/
|
|
|
|
enum meshms_status meshms_mark_read(const sid_t *sender, const sid_t *recipient, uint64_t offset);
|
|
|
|
|
2014-01-22 06:11:22 +00:00
|
|
|
#endif // __SERVAL_DNA__MESHMS_H
|