#pragma once #include #include #include typedef uint8_t byte; typedef byte hash[ 32 ]; typedef byte public_key[ 32 ]; typedef byte private_key[ 32 ]; typedef byte signature[ 64 ]; typedef byte ipv4[ 4 ]; typedef byte ipv6[ 16 ]; #define MAX_RECIPIENTS 32 struct relay_neighbor { bool active; bool has_ipv4; bool has_ipv6; ipv4 v4_addr; ipv6 v6_addr; }; struct relay_info { byte major_version; byte minor_version; byte motd[ 128 ]; struct { uint16_t retention_hours; bool can_store; byte leading_zeros; bool accepts_plain; } capabilities; struct { uint16_t neighbors; uint64_t held_packets; struct relay_neighbor quick_connect[ 4 ]; } statistics; }; struct data_packet { uint32_t nonce; hash hash; struct { bool encrypted; uint64_t created_time_ms; public_key author; public_key author_signing_pub; uint8_t recipient_count; public_key recipients[ 32 ]; byte data[ 65536 ]; signature signature; } contents; }; // from libsodium #ifndef SIGN_PUBLICKEYBYTES #define SIGN_PUBLICKEYBYTES 32 #endif #ifndef SIGN_SECRETKEYBYTES #define SIGN_SECRETKEYBYTES 64 #endif typedef unsigned char sign_public_key[ SIGN_PUBLICKEYBYTES ]; typedef unsigned char sign_secret_key[ SIGN_SECRETKEYBYTES ]; typedef struct { public_key encryption_pub; private_key encryption_priv; sign_public_key signing_pub; sign_secret_key signing_priv; } keypair; struct data_packet_list { struct data_packet* packets; // caller must free this uint16_t count; uint64_t new_offset; }; typedef enum { MP_CLIENT_SUCCESS = 0, MP_CLIENT_ERROR_NETWORK_FAIL, MP_CLIENT_ERROR_INVALID_ADDRESS, MP_CLIENT_ERROR_CONNECTION_FAILED, MP_CLIENT_ERROR_SEND_FAILED, MP_CLIENT_ERROR_RECV_FAILED, MP_CLIENT_ERROR_SERVER_BUSY, // 418 teapot MP_CLIENT_ERROR_INVALID_RESPONSE, MP_CLIENT_ERROR_DESERIALIZE_FAILED, MP_CLIENT_ERROR_ALLOC_FAILED, MP_CLIENT_ERROR_FILE_NOT_FOUND, MP_CLIENT_ERROR_FILE_READ_FAILED, MP_CLIENT_ERROR_BAD_ARGUMENT, } mp_client_error_t; /** * @brief Get server information and capabilities. * @param ip Server IP address (IPv4 or IPv6). * @param port Server port. * @param out_info Pointer to a struct where the server info will be stored. * @return MP_CLIENT_SUCCESS on success, or an error code on failure. */ mp_client_error_t mp_get_server_info(const char* ip, int port, struct relay_info* out_info); /** * @brief Get a list of neighbors from the server. * @param ip Server IP address. * @param port Server port. * @param count Number of neighbors to request. * @param out_neighbors Pointer to a pointer that will be updated to point to a newly allocated * array of neighbors. The caller is responsible for freeing this memory. * @param out_count Pointer to a byte where the actual number of received neighbors will be stored. * @return MP_CLIENT_SUCCESS on success, or an error code on failure. */ mp_client_error_t mp_get_server_neighbors( const char* ip, int port, byte count, struct relay_neighbor** out_neighbors, byte* out_count); /** * @brief Push a packet to the server. * @param ip Server IP address. * @param port Server port. * @param packet The data packet to push. * @param out_success Pointer to a boolean that will be true if the server accepted the packet, * false otherwise. * @return MP_CLIENT_SUCCESS on success, or an error code on failure. */ mp_client_error_t mp_push_packet(const char* ip, int port, struct data_packet packet, bool* out_success); /** * @brief Get a specific packet from the server by its hash. * @param ip Server IP address. * @param port Server port. * @param packet_hash The hash of the packet to retrieve. * @param out_packet Pointer to a struct where the retrieved packet will be stored. * @return MP_CLIENT_SUCCESS on success, or an error code on failure. */ mp_client_error_t mp_get_packet(const char* ip, int port, const hash packet_hash, struct data_packet* out_packet); /** * @brief Get a batch of packets from the server's firehose stream. * @param ip Server IP address. * @param port Server port. * @param offset The starting offset in the firehose stream. * @param count The maximum number of packets to retrieve. * @param out_list Pointer to a data_packet_list struct. The 'packets' member will be allocated by * the function and must be freed by the caller. * @return MP_CLIENT_SUCCESS on success, or an error code on failure. */ mp_client_error_t mp_get_firehose_packets( const char* ip, int port, uint64_t offset, uint16_t count, struct data_packet_list* out_list); /** * @brief Create a data packet from a raw byte buffer. * @param input The raw data buffer. * @param input_len The length of the data buffer. * @param recipient_count The number of recipients. * @param recipients An array of recipient public keys. * @param author_keys The keypair of the packet author. * @return A new data_packet struct. */ struct data_packet mp_create_packet_from_bytes( const byte* input, size_t input_len, byte recipient_count, hash* recipients, keypair author_keys); /** * @brief Create a data packet by reading the contents from a file. * @param filename The path to the file. * @param recipient_count The number of recipients. * @param recipients An array of recipient public keys. * @param author_keys The keypair of the packet author. * @param out_packet Pointer to a struct where the created packet will be stored. * @return MP_CLIENT_SUCCESS on success, or an error code on failure. */ mp_client_error_t mp_create_packet_from_file( const char* filename, byte recipient_count, hash* recipients, keypair author_keys, struct data_packet* out_packet); /** * @brief Run Proof-of-Work on a packet to find a nonce that satisfies the leading zeros * requirement. * @param packet The input packet. The 'nonce' and 'hash' fields will be modified. * @param leading_zeros The number of leading zero bits required for the hash. * @return The modified packet with a valid nonce and hash. */ struct data_packet mp_run_pow(struct data_packet packet, byte leading_zeros); /** * @brief Generates a new encryption and signing keypair. * @return A new keypair struct. */ keypair mp_generate_keypair(void);