/*
This file is part of GNUnet.
Copyright (C) 2020 GNUnet e.V.
GNUnet is free software: you can redistribute it and/or modify it
under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License,
or (at your option) any later version.
GNUnet 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
Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
SPDX-License-Identifier: AGPL3.0-or-later
*/
/**
* @author Tobias Frisch
*
* @file
* MESSENGER service; manages decentralized chat groups
*
* @defgroup messenger MESSENGER service
* Instant messaging based on the CADET subsystem
*
* @{
*/
#ifndef GNUNET_MESSENGER_SERVICE_H
#define GNUNET_MESSENGER_SERVICE_H
#ifdef __cplusplus
extern "C" {
#if 0 /* keep Emacsens' auto-indent happy */
}
#endif
#endif
#include "platform.h"
#include "gnunet_configuration_lib.h"
#include "gnunet_crypto_lib.h"
#include "gnunet_identity_service.h"
#include "gnunet_mq_lib.h"
#include "gnunet_protocols.h"
#include "gnunet_scheduler_lib.h"
#include "gnunet_time_lib.h"
/**
* Version number of GNUnet Messenger API.
*
* Current version of the Messenger: 0.1
*/
#define GNUNET_MESSENGER_VERSION 0x00000001
/**
* Identifier of GNUnet MESSENGER Service.
*/
#define GNUNET_MESSENGER_SERVICE_NAME "messenger"
/**
* Opaque handle to the messenger
*/
struct GNUNET_MESSENGER_Handle;
/**
* Opaque handle to a room
*/
struct GNUNET_MESSENGER_Room;
/**
* Opaque handle to a contact
*/
struct GNUNET_MESSENGER_Contact;
/**
* Enum for the different supported kinds of messages
*/
enum GNUNET_MESSENGER_MessageKind
{
/**
* The info kind. The message contains a #GNUNET_MESSENGER_MessageInfo body.
*/
GNUNET_MESSENGER_KIND_INFO = 1,
/**
* The join kind. The message contains a #GNUNET_MESSENGER_MessageJoin body.
*/
GNUNET_MESSENGER_KIND_JOIN = 2,
/**
* The leave kind. The message contains a #GNUNET_MESSENGER_MessageLeave body.
*/
GNUNET_MESSENGER_KIND_LEAVE = 3,
/**
* The name kind. The message contains a #GNUNET_MESSENGER_MessageName body.
*/
GNUNET_MESSENGER_KIND_NAME = 4,
/**
* The key kind. The message contains a #GNUNET_MESSENGER_MessageKey body.
*/
GNUNET_MESSENGER_KIND_KEY = 5,
/**
* The peer kind. The message contains a #GNUNET_MESSENGER_MessagePeer body.
*/
GNUNET_MESSENGER_KIND_PEER = 6,
/**
* The id kind. The message contains a #GNUNET_MESSENGER_MessageId body.
*/
GNUNET_MESSENGER_KIND_ID = 7,
/**
* The miss kind. The message contains a #GNUNET_MESSENGER_MessageMiss body.
*/
GNUNET_MESSENGER_KIND_MISS = 8,
/**
* The merge kind. The message contains a #GNUNET_MESSENGER_MessageMerge body.
*/
GNUNET_MESSENGER_KIND_MERGE = 9,
/**
* The request kind. The message contains a #GNUNET_MESSENGER_MessageRequest body.
*/
GNUNET_MESSENGER_KIND_REQUEST = 10,
/**
* The invite kind. The message contains a #GNUNET_MESSENGER_MessageInvite body.
*/
GNUNET_MESSENGER_KIND_INVITE = 11,
/**
* The text kind. The message contains a #GNUNET_MESSENGER_MessageText body.
*/
GNUNET_MESSENGER_KIND_TEXT = 12,
/**
* The file kind. The message contains a #GNUNET_MESSENGER_MessageFile body.
*/
GNUNET_MESSENGER_KIND_FILE = 13,
/**
* The private kind. The message contains a #GNUNET_MESSENGER_MessagePrivate body.
*/
GNUNET_MESSENGER_KIND_PRIVATE = 14,
/**
* The delete kind. The message contains a #GNUNET_MESSENGER_MessageDelete body.
*/
GNUNET_MESSENGER_KIND_DELETE = 15,
/**
* The unknown kind. The message contains an unknown body.
*/
GNUNET_MESSENGER_KIND_UNKNOWN = 0
};
#define GNUNET_MESSENGER_KIND_MAX (GNUNET_MESSENGER_KIND_DELETE)
/**
* Get the name of a message kind.
*
* @param kind Kind of a message
* @return Name of that kind
*/
const char*
GNUNET_MESSENGER_name_of_kind (enum GNUNET_MESSENGER_MessageKind kind);
/**
* The header of a #GNUNET_MESSENGER_Message.
* This allows authentication of the sender, temporal ordering and finding potentially missed messages.
*
* Message-header-size: 40+ bytes
*/
struct GNUNET_MESSENGER_MessageHeader
{
/**
* The signature of the senders private key.
*/
struct GNUNET_IDENTITY_Signature signature;
/**
* The timestamp of the message.
*/
struct GNUNET_TIME_AbsoluteNBO timestamp;
/**
* The senders id inside of the room the message was sent in.
*/
struct GNUNET_ShortHashCode sender_id;
/**
* The hash of the previous message from the senders perspective.
*/
struct GNUNET_HashCode previous;
/**
* The kind of the message.
*/
enum GNUNET_MESSENGER_MessageKind kind;
};
/**
* An info message body.
* This allows ensuring member ids are unique and this first message can be verified.
*
* Message-body-size: 8+ bytes
*/
struct GNUNET_MESSENGER_MessageInfo
{
/**
* The senders key to verify its signatures.
*/
struct GNUNET_IDENTITY_PublicKey host_key;
/**
* The version of GNUnet Messenger API.
*
* The sixteen lower bits represent the lower version number while the sixteen higher bits
* represent the higher version number. A different higher version number implies imcompatibility
* to lower versions while differences in the lower version can still be supported potentially.
*/
uint32_t messenger_version;
};
/**
* A join message body.
* This allows informing others about joining the room with a given key pair.
*
* Message-body-size: 4+ bytes
*/
struct GNUNET_MESSENGER_MessageJoin
{
/**
* The senders public key to verify its signatures.
*/
struct GNUNET_IDENTITY_PublicKey key;
};
/**
* A leave message body.
* This allows informing others about leaving the room.
*
* Message-body-size: 0 bytes
*/
struct GNUNET_MESSENGER_MessageLeave
{
};
/**
* A name message body.
* This allows replacing the current name with another one.
*
* Message-body-size: 0+ bytes
*/
struct GNUNET_MESSENGER_MessageName
{
/**
* The new name which replaces the current senders name.
*/
char *name;
};
/**
* A key message body.
* This allows replacing the current key pair with another one.
*
* Message-body-size: 4+ bytes
*/
struct GNUNET_MESSENGER_MessageKey
{
/**
* The new public key which replaces the current senders public key.
*/
struct GNUNET_IDENTITY_PublicKey key;
};
/**
* A peer message body.
* This allows informing others to open a peer as a door to the current room.
*
* Message-body-size: 32 bytes
*/
struct GNUNET_MESSENGER_MessagePeer
{
/**
* The peer identity of the sender opening a room.
*/
struct GNUNET_PeerIdentity peer;
};
/**
* An id message body.
* This allows replacing the member id with a newly unique generated one.
*
* Message-body-size: 8 bytes
*/
struct GNUNET_MESSENGER_MessageId
{
/**
* The new id which will replace the senders id in a room.
*/
struct GNUNET_ShortHashCode id;
};
/**
* A miss message body.
* This allows informing others about a disconnection of any door.
*
* Message-body-size: 32 bytes
*/
struct GNUNET_MESSENGER_MessageMiss
{
/**
* The peer identity of a disconnected door to a room.
*/
struct GNUNET_PeerIdentity peer;
};
/**
* A merge message body.
* This allows merging message history branches together.
*
* Message-body-size: 16 bytes
*/
struct GNUNET_MESSENGER_MessageMerge
{
/**
* The hash of a second previous message.
*/
struct GNUNET_HashCode previous;
};
/**
* A request message body.
* This allows requesting the content of a specific message which is currently missing.
*
* Message-body-size: 16 bytes
*/
struct GNUNET_MESSENGER_MessageRequest
{
/**
* The hash of the requested message.
*/
struct GNUNET_HashCode hash;
};
/**
* An invite message body.
* This allows sharing information about other rooms in form of an invitation.
*
* Message-body-size: 48 bytes
*/
struct GNUNET_MESSENGER_MessageInvite
{
/**
* The peer identity of an open door to a room.
*/
struct GNUNET_PeerIdentity door;
/**
* The hash identifying the port of the room.
*/
struct GNUNET_HashCode key;
};
/**
* A text message body.
* This allows general communication in text form.
*
* Message-body-size: 0+ bytes
*/
struct GNUNET_MESSENGER_MessageText
{
/**
* The containing text.
*/
char *text;
};
/**
* A file message body.
* This allows sending necessary details about an uploaded encrypted file to allow access to it.
*
* Message-body-size: 335+ bytes
*/
struct GNUNET_MESSENGER_MessageFile
{
/**
* The symmetric key to decrypt the file.
*/
struct GNUNET_CRYPTO_SymmetricSessionKey key;
/**
* The hash of the original file.
*/
struct GNUNET_HashCode hash;
/**
* The name of the original file.
*/
char name[NAME_MAX];
/**
* The uri of the encrypted file.
*/
char *uri;
};
/**
* A private message body.
* This allows to encapsulate any message to be encrypted for only one specific member to receive in a room.
*
* Message-body-size: 32+ bytes
*/
struct GNUNET_MESSENGER_MessagePrivate
{
/**
* The ECDH key to decrypt the message.
*/
struct GNUNET_CRYPTO_EcdhePublicKey key;
/**
* The length of the encrypted message.
*/
uint16_t length;
/**
* The data of the encrypted message.
*/
char *data;
};
/**
* A delete message body
* This allows deletion of an own previous message with any custom automatic delay.
*
* Message-body-size: 24 bytes
*/
struct GNUNET_MESSENGER_MessageDelete
{
/**
* The hash of the message to delete.
*/
struct GNUNET_HashCode hash;
/**
* The delay of the delete operation to get processed.
*/
struct GNUNET_TIME_RelativeNBO delay;
};
/**
* The unified body of a #GNUNET_MESSENGER_Message.
*/
struct GNUNET_MESSENGER_MessageBody
{
union
{
struct GNUNET_MESSENGER_MessageInfo info;
struct GNUNET_MESSENGER_MessageJoin join;
struct GNUNET_MESSENGER_MessageLeave leave;
struct GNUNET_MESSENGER_MessageName name;
struct GNUNET_MESSENGER_MessageKey key;
struct GNUNET_MESSENGER_MessagePeer peer;
struct GNUNET_MESSENGER_MessageId id;
struct GNUNET_MESSENGER_MessageMiss miss;
struct GNUNET_MESSENGER_MessageMerge merge;
struct GNUNET_MESSENGER_MessageRequest request;
struct GNUNET_MESSENGER_MessageInvite invite;
struct GNUNET_MESSENGER_MessageText text;
struct GNUNET_MESSENGER_MessageFile file;
struct GNUNET_MESSENGER_MessagePrivate private;
struct GNUNET_MESSENGER_MessageDelete delete;
};
};
/**
* Struct to a message
*/
struct GNUNET_MESSENGER_Message
{
/**
* Header.
*/
struct GNUNET_MESSENGER_MessageHeader header;
/**
* Body
*/
struct GNUNET_MESSENGER_MessageBody body;
};
/**
* Enum for the different supported flags used by message handling
*/
enum GNUNET_MESSENGER_MessageFlags
{
/**
* The none flag. The flag indicates that the message is not affected by any special context.
*/
GNUNET_MESSENGER_FLAG_NONE = 0,
/**
* The private flag. The flag indicates that the message was privately encrypted.
*/
GNUNET_MESSENGER_FLAG_PRIVATE = 1,
};
/**
* Method called whenever the EGO of a handle changes or if the first connection fails
* to load a valid EGO and the anonymous key pair will be used instead.
*
* @param[in/out] cls Closure from #GNUNET_MESSENGER_connect
* @param[in/out] handle Messenger handle
*/
typedef void
(*GNUNET_MESSENGER_IdentityCallback) (void *cls, struct GNUNET_MESSENGER_Handle *handle);
/**
* Method called whenever a message is sent or received from a room.
*
* The flag private_message will be #GNUNET_YES if a message was
* received privately, otherwise #GNUNET_NO.
*
* @param[in/out] cls Closure from #GNUNET_MESSENGER_connect
* @param[in] room Room handle
* @param[in] sender Sender of message
* @param[in] message Newly received or sent message
* @param[in] hash Hash identifying the message
* @param[in] flags Flags of the message
*/
typedef void
(*GNUNET_MESSENGER_MessageCallback) (void *cls, struct GNUNET_MESSENGER_Room *room,
const struct GNUNET_MESSENGER_Contact *sender,
const struct GNUNET_MESSENGER_Message *message,
const struct GNUNET_HashCode *hash,
enum GNUNET_MESSENGER_MessageFlags flags);
/**
* Method called for each member in a room during iteration. If the method returns
* #GNUNET_YES the iteration continues, otherwise it will quit the iteration.
*
* @param[in/out] cls Closure from #GNUNET_MESSENGER_iterate_members
* @param[in] room Room handle
* @param[in] contact Contact handle
*/
typedef int
(*GNUNET_MESSENGER_MemberCallback) (void* cls, struct GNUNET_MESSENGER_Room *room,
const struct GNUNET_MESSENGER_Contact *contact);
/**
* Set up a handle for the messenger related functions and connects to all necessary services. It will look up the ego
* key identified by its name and use it for signing all messages from the handle.
*
* @param[in] cfg Configuration to use
* @param[in] name Name to look up an ego or NULL to stay anonymous
* @param[in] identity_callback Function called when the EGO of the handle changes
* @param[in/out] identity_cls Closure for the identity_callback handler
* @param[in] msg_callback Function called when a new message is sent or received
* @param[in/out] msg_cls Closure for the msg_callback handler
* @return Messenger handle to use, NULL on error
*/
struct GNUNET_MESSENGER_Handle*
GNUNET_MESSENGER_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *name,
GNUNET_MESSENGER_IdentityCallback identity_callback, void *identity_cls,
GNUNET_MESSENGER_MessageCallback msg_callback, void *msg_cls);
/**
* Update a handle of the messenger to use a different ego key and replace the old one with a newly generated one. All
* participated rooms get informed about the key renewal. The handle requires a set name for this function to work and
* it needs to be unused by other egos.
*
* Keep in mind that this will fully delete the old ego key (if any is used) even if any other service wants to use it
* as default.
*
* @param[in/out] handle Messenger handle to use
* @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
*/
int
GNUNET_MESSENGER_update (struct GNUNET_MESSENGER_Handle *handle);
/**
* Disconnect all of the messengers used services and clears up its used memory.
*
* @param[in/out] handle Messenger handle to use
*/
void
GNUNET_MESSENGER_disconnect (struct GNUNET_MESSENGER_Handle *handle);
/**
* Get the name (if specified, otherwise NULL) used by the messenger.
*
* @param[in] handle Messenger handle to use
* @return Name used by the messenger or NULL
*/
const char*
GNUNET_MESSENGER_get_name (const struct GNUNET_MESSENGER_Handle *handle);
/**
* Set the name for the messenger. This will rename the currently used ego and move all stored files related to the current
* name to its new directory. If anything fails during this process the function returns #GNUNET_NO and the name for
* the messenger won't change as specified.
*
* @param[in/out] handle Messenger handle to use
* @param[in] name Name for the messenger to change to
* @return #GNUNET_YES on success, #GNUNET_NO on failure and #GNUNET_SYSERR if handle is NULL
*/
int
GNUNET_MESSENGER_set_name (struct GNUNET_MESSENGER_Handle *handle, const char *name);
/**
* Get the public key used by the messenger or NULL if the anonymous key was used.
*
* @param[in] handle Messenger handle to use
* @return Used ego's public key or NULL
*/
const struct GNUNET_IDENTITY_PublicKey*
GNUNET_MESSENGER_get_key (const struct GNUNET_MESSENGER_Handle *handle);
/**
* Open a room to send and receive messages. The room will use the specified key as port for the underlying cadet
* service. Opening a room results in opening the port for incoming connections as possible door.
*
* Notice that there can only be one room related to a specific key. So trying to open two rooms with the same
* key will result in opening the room once but returning the handle both times because the room stays open.
*
* You can also open a room after entering it through a door using #GNUNET_MESSENGER_enter_room. This
* will notify all entered doors to list you as new door.
*
* ( All doors form a ring structured network to shorten the latency sending and receiving messages. )
*
* @param[in/out] handle Messenger handle to use
* @param[in] key Hash identifying the port
* @return Room handle, NULL on error
*/
struct GNUNET_MESSENGER_Room*
GNUNET_MESSENGER_open_room (struct GNUNET_MESSENGER_Handle *handle, const struct GNUNET_HashCode *key);
/**
* Enter a room to send and receive messages through a door opened using #GNUNET_MESSENGER_open_room.
*
* Notice that there can only be one room related to a specific key. So trying to enter two rooms with the same
* key will result in entering the room once but returning the handle both times because the room stays entered.
* You can however enter a room through multiple doors in parallel which results in connecting both ends. But
* entering the room through the same door won't have any effect after the first time.
*
* You can also enter a room through a door after opening it using #GNUNET_MESSENGER_open_room. But the
* door may not be your own peer identity.
*
* ( All doors form a ring structured network to shorten the latency sending and receiving messages. )
*
* @param[in/out] handle Messenger handle to use
* @param[in] door Peer identity of an open door
* @param[in] key Hash identifying the port
* @return Room handle, NULL on error
*/
struct GNUNET_MESSENGER_Room*
GNUNET_MESSENGER_enter_room (struct GNUNET_MESSENGER_Handle *handle, const struct GNUNET_PeerIdentity *door,
const struct GNUNET_HashCode *key);
/**
* Close a room which was entered, opened or both in various order and variety. Closing a room will destroy all connections
* from your peer to another and the other way around.
*
* ( After a member closes a door, all members entered through that specific door have to use another one
* or open the room on their own. )
*
* @param[in/out] room Room handle
*/
void
GNUNET_MESSENGER_close_room (struct GNUNET_MESSENGER_Room *room);
/**
* Searches for a specific contact in a given room and calls a selected callback with a given
* closure for each of them containing the contact as a member. The callback will receive a room matching the condition
* and the given contact. The function returns the amount of rooms iterated with the given callback.
*
* @param[in] handle Messenger handle to use
* @param[in] contact Contact handle
* @param[in] callback Function called for each room
* @param[in] cls Closure for the callback handler
* @return Amount of rooms iterated
*/
int
GNUNET_MESSENGER_find_rooms (const struct GNUNET_MESSENGER_Handle *handle, const struct GNUNET_MESSENGER_Contact *contact,
GNUNET_MESSENGER_MemberCallback callback, void *cls);
/**
* Get the contact of a member in a room which sent a specific message identified with a given hash.
*
* Notice that contacts are independent of rooms but will be removed if all rooms containing these contacts get closed.
*
* @param[in] room Room handle
* @param[in] hash Hash identifying a message
* @return Contact handle, NULL otherwise
*/
struct GNUNET_MESSENGER_Contact*
GNUNET_MESSENGER_get_sender (const struct GNUNET_MESSENGER_Room *room, const struct GNUNET_HashCode *hash);
/**
* Get the name used by the contact.
*
* @param[in] contact Contact handle
* @return Name of contact or NULL
*/
const char*
GNUNET_MESSENGER_contact_get_name (const struct GNUNET_MESSENGER_Contact *contact);
/**
* Get the public key used by the contact or NULL if the anonymous key was used.
*
* @param[in] contact Contact handle
* @return Public key of the ego used by contact or NULL
*/
const struct GNUNET_IDENTITY_PublicKey*
GNUNET_MESSENGER_contact_get_key (const struct GNUNET_MESSENGER_Contact *contact);
/**
* Send a message into a room. If you opened the room all entered members will receive the
* message. If you entered the room through a door all so entered doors will receive the
* message as well. All members receiving the message will also propagate this message recursively
* as long as the message is unknown to them.
*
* Notice that all messages sent and received are also stored and can be propagated to new members entering the room.
*
* If you provide a specific contact as receiver of the given message, the message will automatically be
* encrypted and sent as a private message (see #GNUNET_MESSENGER_MessagePrivate). Therefore the selected contact
* will be the only member receiving the actual message.
*
* Sending a message to all members in a given room can be done by providing NULL as contact.
*
* @param[in/out] room Room handle
* @param[in] message New message to send
* @param[in] contact Contact or NULL
*/
void
GNUNET_MESSENGER_send_message (struct GNUNET_MESSENGER_Room *room, const struct GNUNET_MESSENGER_Message *message,
const struct GNUNET_MESSENGER_Contact* contact);
/**
* Get the message in a room identified by its hash.
*
* @param[in] room Room handle
* @param[in] hash Hash identifying a message
* @return Message struct or NULL if no message with that hash is known
*/
const struct GNUNET_MESSENGER_Message*
GNUNET_MESSENGER_get_message (const struct GNUNET_MESSENGER_Room *room, const struct GNUNET_HashCode *hash);
/**
* Iterates through all members of a given room and calls a selected callback
* for each of them with a provided closure. The callback will receive the contact of each
* member. The function returns the amount of members iterated with the given callback.
*
* @param[in] room Room handle
* @param[in] callback Function called for each member
* @param[in] cls Closure for the callback handler
* @return Amount of members iterated
*/
int
GNUNET_MESSENGER_iterate_members (struct GNUNET_MESSENGER_Room *room, GNUNET_MESSENGER_MemberCallback callback,
void* cls);
#if 0 /* keep Emacsens' auto-indent happy */
{
#endif
#ifdef __cplusplus
}
#endif
#endif //GNUNET_MESSENGER_SERVICE_H
/** @} *//* end of group */