summaryrefslogtreecommitdiff
path: root/client/client.h
blob: a2a6a28b5522a616f18c66ed53db72759a27227f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
#pragma once

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

typedef uint8_t byte;
typedef byte    hash[ 32 ];
typedef byte    public_key[ 32 ];
typedef byte    private_key[ 32 ];
typedef byte    recipient[ 64 ];
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;
        recipient 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,
    recipient*       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,
    recipient*               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);