0.0.002
ddat interop with dat js cable interop with cabal js ddat's frontend = dat-thang cable fe = cable-thang dillo support based on cel's dillo-dat bootstrap node xplatform support Signed-off-by: divo <418@cryspace.space>
This commit is contained in:
1 parent
f0f91540be
commit
b735900f2e
323 files changed
+134347
-343
No files matched your search
@@ -0,0 +1,17 @@
|
||||
#ifndef BASE32768_H
|
||||
#define BASE32768_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* UTF-8 C-string form of qntm/base32768's BMP-safe Base32768 encoding. */
|
||||
int base32768_encode(const uint8_t *input, size_t input_length,
|
||||
char *output, size_t output_capacity);
|
||||
int base32768_decode(const char *input, uint8_t *output,
|
||||
size_t output_capacity, size_t *output_length);
|
||||
|
||||
/* Enumerate the alphabet: bits=15 selects the 32,768 main characters;
|
||||
* bits=7 selects the 128 possible final padding characters. */
|
||||
int base32768_codepoint_at(unsigned bits, uint32_t index, uint32_t *codepoint);
|
||||
|
||||
#endif
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
#ifndef CABLE_H
|
||||
#define CABLE_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "keys.h"
|
||||
#include "sleep_feed.h"
|
||||
|
||||
#define CABLE_KEY_BYTES 32u
|
||||
#define CABLE_CHAT_TEXT_BYTES 768u
|
||||
#define CABLE_CHAT_WIRE_BYTES (4u + 8u + 2u + CABLE_CHAT_TEXT_BYTES)
|
||||
#define CABLE_CHAT_SEAL_BYTES (CABLE_CHAT_WIRE_BYTES + 48u)
|
||||
|
||||
enum cable_address_scheme {
|
||||
CABLE_ADDRESS_CABAL = 1,
|
||||
CABLE_ADDRESS_CABLE = 2,
|
||||
CABLE_ADDRESS_HYPER = 3
|
||||
};
|
||||
|
||||
typedef struct cable_chat_message {
|
||||
uint64_t timestamp_ms;
|
||||
char text[CABLE_CHAT_TEXT_BYTES + 1u];
|
||||
size_t text_length;
|
||||
} cable_chat_message_t;
|
||||
|
||||
/* A Cabal user address is that user's persistent feed public key. A room
|
||||
* address may additionally carry a room moderation/admin key. */
|
||||
typedef struct cable_room_address {
|
||||
uint8_t key[CABLE_KEY_BYTES];
|
||||
uint8_t admin_key[CABLE_KEY_BYTES];
|
||||
enum cable_address_scheme scheme;
|
||||
int has_admin;
|
||||
} cable_room_address_t;
|
||||
|
||||
/* The schemes share a 32-byte key representation; the caller decides whether
|
||||
* it is a room key or a user feed key. hyper:// is a migration alias only. */
|
||||
int cable_address_parse(const char *address, uint8_t key[CABLE_KEY_BYTES],
|
||||
enum cable_address_scheme *scheme);
|
||||
int cable_address_format(const uint8_t key[CABLE_KEY_BYTES],
|
||||
enum cable_address_scheme scheme, char *out, size_t capacity);
|
||||
int cable_room_address_parse(const char *address, cable_room_address_t *room);
|
||||
int cable_room_address_format(const cable_room_address_t *room,
|
||||
enum cable_address_scheme scheme, char *out, size_t capacity);
|
||||
int cable_user_address_format(const uint8_t user_feed_key[CABLE_KEY_BYTES],
|
||||
enum cable_address_scheme scheme, char *out, size_t capacity);
|
||||
/* Cabal stores the local writer in a room's storage, so derive a per-room
|
||||
* local feed-key path instead of sharing one global identity across rooms. */
|
||||
int cable_user_identity_path(const char *home,
|
||||
const uint8_t room_key[CABLE_KEY_BYTES],
|
||||
char *out, size_t capacity);
|
||||
/* Create a Cabal room signing key and persist it in the room directory. */
|
||||
int cable_room_create(const char *home, uint8_t room_key[CABLE_KEY_BYTES]);
|
||||
/* Store/load the user's local feed secret key. The public key is derived and
|
||||
* checked on load. The file contains only the 64-byte Ed25519 secret key. */
|
||||
int cable_user_identity_load_or_create(const char *path, sleep_keypair_t *identity);
|
||||
/* Cabal stores messages as JSON blocks in each user's Hypercore feed. These
|
||||
* helpers use the same Hypercore 7.x on-disk tree/signature layout. */
|
||||
int cable_user_feed_open(const char *home,
|
||||
const uint8_t room_key[CABLE_KEY_BYTES],
|
||||
sleep_keypair_t *identity, sleep_feed_t *feed);
|
||||
int cable_user_feed_append(const char *home,
|
||||
const uint8_t room_key[CABLE_KEY_BYTES],
|
||||
const uint8_t *record, size_t record_length,
|
||||
uint8_t user_key[CABLE_KEY_BYTES]);
|
||||
int cable_user_feed_publish(const char *home,
|
||||
const uint8_t room_key[CABLE_KEY_BYTES],
|
||||
const char *record_type, const char *nick,
|
||||
const char *channel, const char *text,
|
||||
uint8_t user_key[CABLE_KEY_BYTES]);
|
||||
int cable_chat_message_encode(const cable_chat_message_t *message,
|
||||
uint8_t *out, size_t capacity, size_t *written);
|
||||
int cable_chat_message_decode(cable_chat_message_t *message,
|
||||
const uint8_t *input, size_t length);
|
||||
int cable_chat_seal(const uint8_t recipient_ed25519[32],
|
||||
const uint8_t *message, size_t message_length,
|
||||
uint8_t *out, size_t capacity, size_t *written);
|
||||
int cable_chat_open(const sleep_keypair_t *identity,
|
||||
const uint8_t *sealed, size_t sealed_length,
|
||||
uint8_t *out, size_t capacity, size_t *written);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,56 @@
|
||||
#ifndef CABLE_MEDIA_H
|
||||
#define CABLE_MEDIA_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define CABLE_MEDIA_SESSION_BYTES 16u
|
||||
#define CABLE_MEDIA_HEADER_BYTES 42u
|
||||
#define CABLE_MEDIA_MAX_PACKET_BYTES 4096u
|
||||
#define CABLE_MEDIA_AAC_RATE 48000u
|
||||
#define CABLE_MEDIA_AAC_BITRATE 96000u
|
||||
#define CABLE_MEDIA_AAC_CHANNELS 1u
|
||||
#define CABLE_MEDIA_AAC_SAMPLES 1024u
|
||||
|
||||
enum cable_media_kind {
|
||||
CABLE_MEDIA_AUDIO_START = 1,
|
||||
CABLE_MEDIA_AUDIO_FRAME = 2,
|
||||
CABLE_MEDIA_AUDIO_STOP = 3,
|
||||
CABLE_MEDIA_VIDEO_START = 4,
|
||||
CABLE_MEDIA_VIDEO_FRAME = 5,
|
||||
CABLE_MEDIA_VIDEO_STOP = 6
|
||||
};
|
||||
|
||||
typedef struct cable_media_packet {
|
||||
uint8_t kind;
|
||||
uint8_t session[CABLE_MEDIA_SESSION_BYTES];
|
||||
uint64_t sequence;
|
||||
uint64_t timestamp_us;
|
||||
const uint8_t *payload;
|
||||
size_t payload_length;
|
||||
} cable_media_packet_t;
|
||||
|
||||
int cable_media_packet_write(const cable_media_packet_t *packet,
|
||||
uint8_t *output, size_t capacity, size_t *written);
|
||||
int cable_media_packet_read(cable_media_packet_t *packet,
|
||||
const uint8_t *input, size_t length);
|
||||
|
||||
typedef struct cable_aac_encoder { void *implementation; } cable_aac_encoder_t;
|
||||
typedef struct cable_aac_decoder { void *implementation; } cable_aac_decoder_t;
|
||||
typedef int (*cable_aac_frame_fn)(void *context, const uint8_t *adts,
|
||||
size_t length);
|
||||
typedef int (*cable_pcm_samples_fn)(void *context, const int16_t *samples,
|
||||
size_t sample_count);
|
||||
|
||||
int cable_aac_encoder_open(cable_aac_encoder_t *encoder);
|
||||
int cable_aac_encoder_frame(cable_aac_encoder_t *encoder,
|
||||
const int16_t samples[CABLE_MEDIA_AAC_SAMPLES],
|
||||
cable_aac_frame_fn output, void *context);
|
||||
void cable_aac_encoder_close(cable_aac_encoder_t *encoder);
|
||||
int cable_aac_decoder_open(cable_aac_decoder_t *decoder);
|
||||
int cable_aac_decoder_frame(cable_aac_decoder_t *decoder,
|
||||
const uint8_t *adts, size_t length,
|
||||
cable_pcm_samples_fn output, void *context);
|
||||
void cable_aac_decoder_close(cable_aac_decoder_t *decoder);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,30 @@
|
||||
#ifndef CABLE_ROOM_H
|
||||
#define CABLE_ROOM_H
|
||||
|
||||
#include "cable.h"
|
||||
|
||||
#define CABLE_ROOM_CHANNEL_BYTES 64u
|
||||
#define CABLE_ROOM_NICK_BYTES 64u
|
||||
|
||||
enum cable_room_event_type {
|
||||
CABLE_ROOM_PEER_JOIN = 1,
|
||||
CABLE_ROOM_PEER_LEAVE = 2,
|
||||
CABLE_ROOM_NICK = 3,
|
||||
CABLE_ROOM_CHANNEL_JOIN = 4,
|
||||
CABLE_ROOM_TEXT = 5
|
||||
};
|
||||
|
||||
typedef struct cable_room_event {
|
||||
uint8_t type;
|
||||
uint64_t timestamp_ms;
|
||||
uint8_t sender[CABLE_KEY_BYTES];
|
||||
char channel[CABLE_ROOM_CHANNEL_BYTES + 1u];
|
||||
char nick[CABLE_ROOM_NICK_BYTES + 1u];
|
||||
char text[CABLE_CHAT_TEXT_BYTES + 1u];
|
||||
size_t text_length;
|
||||
} cable_room_event_t;
|
||||
|
||||
/* In-memory UI event only. Cable's network records are Cabal Core Hypercore
|
||||
* values and never serialize this C structure. */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,22 @@
|
||||
#ifndef CABLE_VIDEO_H
|
||||
#define CABLE_VIDEO_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct cable_video_source cable_video_source_t;
|
||||
|
||||
/* Read an OBS MPEG-TS feed from a local UDP socket, normally port 5000.
|
||||
* Pixels are copied as RGB24; a generation change means a new frame arrived. */
|
||||
cable_video_source_t *cable_video_source_open(const char *url);
|
||||
void cable_video_source_close(cable_video_source_t *source);
|
||||
int cable_video_source_frame(cable_video_source_t *source, uint8_t *rgb,
|
||||
size_t capacity, unsigned *width, unsigned *height,
|
||||
uint64_t *generation);
|
||||
/* Encode/decode one low-resolution JPEG frame for volatile Cable media. */
|
||||
int cable_video_encode_jpeg(const uint8_t *rgb, unsigned width, unsigned height,
|
||||
uint8_t *jpeg, size_t capacity, size_t *written);
|
||||
int cable_video_decode_jpeg(const uint8_t *jpeg, size_t length, uint8_t *rgb,
|
||||
size_t capacity, unsigned *width, unsigned *height);
|
||||
|
||||
#endif
|
||||
+7
-12
@@ -1,14 +1,9 @@
|
||||
#ifndef CESSPOOL_H
|
||||
#define CESSPOOL_H
|
||||
#ifndef CESSPOOL_COMPAT_H
|
||||
#define CESSPOOL_COMPAT_H
|
||||
|
||||
#include "key.h"
|
||||
/* Compatibility include for existing Dat/Cable modules. The public Cesspool
|
||||
* API and its independent network types live in libcess/include. */
|
||||
#include <libcess/cesspool.h>
|
||||
#include "dat_net.h"
|
||||
|
||||
// bootstrap node
|
||||
// dht
|
||||
// discovery
|
||||
// lookup (key) ↳ lookup1
|
||||
// announce
|
||||
// ping
|
||||
// holepunch udp
|
||||
|
||||
#endif /* CESSPOOL_H */
|
||||
#endif
|
||||
@@ -1,4 +1,114 @@
|
||||
#ifndef DAT_H
|
||||
#define DAT_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "keys.h"
|
||||
#include "sleep_proto.h"
|
||||
|
||||
#define DAT_KEY_BYTES 32u
|
||||
#define DAT_BLOCK_BYTES (64u * 1024u)
|
||||
#define DAT_URL_BYTES 71u
|
||||
#define DAT_LINK_BYTES 4096u
|
||||
|
||||
typedef struct dat_archive {
|
||||
char dat_path[1024];
|
||||
uint8_t metadata_key[DAT_KEY_BYTES];
|
||||
uint8_t content_key[DAT_KEY_BYTES];
|
||||
sleep_keypair_t metadata_keys;
|
||||
sleep_keypair_t content_keys;
|
||||
} dat_archive_t;
|
||||
typedef struct dat_link {
|
||||
uint8_t key[DAT_KEY_BYTES];
|
||||
uint64_t version;
|
||||
int has_version;
|
||||
char path[2048];
|
||||
} dat_link_t;
|
||||
typedef struct dat_checkout {
|
||||
const dat_archive_t *archive;
|
||||
uint64_t version;
|
||||
} dat_checkout_t;
|
||||
typedef struct dat_url {
|
||||
char host[256];
|
||||
char path[2048];
|
||||
uint64_t version;
|
||||
int has_version;
|
||||
int wants_stat;
|
||||
int force_directory_listing;
|
||||
} dat_url_t;
|
||||
typedef struct dat_path_info {
|
||||
sleep_metadata_entry_t entry;
|
||||
int exists;
|
||||
int is_directory;
|
||||
} dat_path_info_t;
|
||||
typedef int (*dat_archive_change_fn)(const sleep_metadata_entry_t *entry,
|
||||
uint64_t version, void *context);
|
||||
typedef int (*dat_archive_readdir_fn)(const sleep_metadata_entry_t *entry,
|
||||
const char *name, void *context);
|
||||
|
||||
/* Creates a new two-feed legacy-style archive skeleton under root/.dat. */
|
||||
int dat_archive_create(dat_archive_t *archive, const char *root);
|
||||
int dat_archive_open(dat_archive_t *archive, const char *root);
|
||||
int dat_archive_open_writable(dat_archive_t *archive, const char *root,
|
||||
const char *secret_directory);
|
||||
int dat_archive_save_secrets(const dat_archive_t *archive,
|
||||
const char *secret_directory);
|
||||
void dat_archive_close(dat_archive_t *archive);
|
||||
size_t dat_archive_entry_count(const dat_archive_t *archive);
|
||||
uint64_t dat_archive_version(const dat_archive_t *archive);
|
||||
int dat_archive_append_file(dat_archive_t *archive, const char *path,
|
||||
const uint8_t *data, size_t length,
|
||||
uint32_t mode, uint64_t mtime);
|
||||
int dat_archive_append_directory(dat_archive_t *archive, const char *path,
|
||||
uint32_t mode, uint64_t mtime);
|
||||
int dat_archive_append_symlink(dat_archive_t *archive, const char *path,
|
||||
const char *target, uint64_t mtime);
|
||||
int dat_archive_delete(dat_archive_t *archive, const char *path, uint64_t mtime);
|
||||
int dat_archive_read_entry(const dat_archive_t *archive, size_t index,
|
||||
sleep_metadata_entry_t *entry);
|
||||
int dat_archive_read_file(const dat_archive_t *archive,
|
||||
const sleep_metadata_entry_t *entry,
|
||||
uint8_t **data, size_t *length);
|
||||
int dat_archive_find(const dat_archive_t *archive, const char *path,
|
||||
sleep_metadata_entry_t *entry);
|
||||
int dat_archive_find_at(const dat_archive_t *archive, const char *path,
|
||||
uint64_t version, sleep_metadata_entry_t *entry);
|
||||
int dat_checkout_init(dat_checkout_t *checkout, const dat_archive_t *archive,
|
||||
uint64_t version);
|
||||
int dat_checkout_find(const dat_checkout_t *checkout, const char *path,
|
||||
sleep_metadata_entry_t *entry);
|
||||
int dat_checkout_read(const dat_checkout_t *checkout,
|
||||
const sleep_metadata_entry_t *entry,
|
||||
uint8_t **data, size_t *length);
|
||||
int dat_checkout_export(const dat_checkout_t *checkout, const char *archive_path,
|
||||
const char *filesystem_path);
|
||||
int dat_archive_changes(const dat_archive_t *archive, uint64_t from_version,
|
||||
uint64_t to_version, dat_archive_change_fn callback, void *context);
|
||||
int dat_archive_stat_at(const dat_archive_t *archive, uint64_t version,
|
||||
const char *path, dat_path_info_t *info);
|
||||
int dat_archive_readdir_at(const dat_archive_t *archive, uint64_t version,
|
||||
const char *path, dat_archive_readdir_fn callback,
|
||||
void *context);
|
||||
int dat_archive_resolve_at(const dat_archive_t *archive, uint64_t version,
|
||||
const char *path, int force_directory_listing,
|
||||
dat_path_info_t *info, int *serve_directory_listing);
|
||||
const char *dat_content_type(const char *path);
|
||||
int dat_url_parse(const char *text, dat_url_t *url);
|
||||
int dat_archive_import_path(dat_archive_t *archive, const char *filesystem_path,
|
||||
const char *archive_path);
|
||||
/* Imports only changed paths and records tombstones for paths removed locally. */
|
||||
int dat_archive_sync_path(dat_archive_t *archive, const char *filesystem_path,
|
||||
const char *archive_path);
|
||||
int dat_archive_export_path(const dat_archive_t *archive, const char *archive_path,
|
||||
const char *filesystem_path);
|
||||
int dat_archive_export_at(const dat_archive_t *archive, uint64_t version,
|
||||
const char *archive_path, const char *filesystem_path);
|
||||
int dat_key_to_url(const uint8_t key[DAT_KEY_BYTES], char url[DAT_URL_BYTES]);
|
||||
int dat_key_to_compact_url(const uint8_t key[DAT_KEY_BYTES], char url[DAT_URL_BYTES]);
|
||||
int dat_key_to_hex(const uint8_t key[DAT_KEY_BYTES], char hex[65]);
|
||||
int dat_url_to_key(const char *url, uint8_t key[DAT_KEY_BYTES]);
|
||||
int dat_link_format(const dat_link_t *link, char *out, size_t capacity);
|
||||
int dat_link_format_compact(const dat_link_t *link, char *out, size_t capacity);
|
||||
int dat_link_parse(const char *text, dat_link_t *link);
|
||||
|
||||
#endif /* DAT_H */
|
||||
@@ -0,0 +1,27 @@
|
||||
#ifndef DAT_DNS_H
|
||||
#define DAT_DNS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "dat.h"
|
||||
|
||||
typedef int (*dat_dns_name_iter_fn)(const char *hostname,
|
||||
const uint8_t key[DAT_KEY_BYTES], void *context);
|
||||
|
||||
/* Resolve a legacy Dat DNS TXT record such as datkey=<64 hex digits>. */
|
||||
int dat_dns_resolve(const char *hostname, uint8_t key[DAT_KEY_BYTES],
|
||||
uint32_t *ttl_seconds);
|
||||
|
||||
/* Local dat-dns aliases are stored in $HOME/.dat/dat-dns (or USERPROFILE on
|
||||
* native Windows) and override DNS TXT. */
|
||||
int dat_dns_name_set(const char *hostname, const uint8_t key[DAT_KEY_BYTES]);
|
||||
int dat_dns_name_remove(const char *hostname);
|
||||
int dat_dns_name_resolve(const char *hostname, uint8_t key[DAT_KEY_BYTES]);
|
||||
int dat_dns_name_for_key(const uint8_t key[DAT_KEY_BYTES], char *hostname,
|
||||
size_t hostname_capacity);
|
||||
int dat_dns_name_foreach(dat_dns_name_iter_fn callback, void *context);
|
||||
|
||||
/* Decode TXT record character strings from one DNS answer packet. */
|
||||
int dat_dns_parse_answer(const uint8_t *packet, unsigned packet_len,
|
||||
uint8_t key[DAT_KEY_BYTES], uint32_t *ttl_seconds);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
#ifndef DAT_FETCH_H
|
||||
#define DAT_FETCH_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Fetch the public metadata and content feeds for a Dat key into root/.dat.
|
||||
* The fetch uses the configured Cesspool network and persists verified sparse
|
||||
* feed blocks so a later Dillo request can resume it. */
|
||||
int dat_fetch_archive(const char *root, const uint8_t metadata_key[32],
|
||||
unsigned timeout_ms);
|
||||
|
||||
#endif
|
||||
+18
-29
@@ -1,33 +1,22 @@
|
||||
#ifndef DAT_NET_H
|
||||
#define DAT_NET_H
|
||||
#ifndef DAT_NET_COMPAT_H
|
||||
#define DAT_NET_COMPAT_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/socket.h>
|
||||
/* Source-compatibility names for Dat/Cable code written before libcess was
|
||||
* extracted. New integrations should include <cess_net.h> directly. */
|
||||
#include <libcess/cess_net.h>
|
||||
#include "dat_socket.h"
|
||||
|
||||
#define DATNET_PORT 3282
|
||||
#define DATNET_MAX_PACKET 1400
|
||||
#define DATNET_TOPIC_BYTES 32
|
||||
#define DATNET_PEERID_BYTES 32
|
||||
typedef cess_peer_t dat_peer_t;
|
||||
typedef cessnet_t datnet_t;
|
||||
|
||||
typedef struct {
|
||||
int fd;
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t addrlen;
|
||||
uint8_t id[DATNET_PEERID_BYTES];
|
||||
} dat_peer_t;
|
||||
#define DATNET_PORT CESSNET_PORT
|
||||
#define DATNET_MAX_PACKET CESSNET_MAX_PACKET
|
||||
#define DATNET_TOPIC_BYTES CESSNET_TOPIC_BYTES
|
||||
#define DATNET_PEERID_BYTES CESSNET_PEERID_BYTES
|
||||
#define datnet_init cessnet_init
|
||||
#define datnet_bind cessnet_bind
|
||||
#define datnet_poll cessnet_poll
|
||||
#define datnet_send cessnet_send
|
||||
#define datnet_close cessnet_close
|
||||
|
||||
typedef struct {
|
||||
int sock;
|
||||
uint8_t topic[DATNET_TOPIC_BYTES];
|
||||
uint8_t peerid[DATNET_PEERID_BYTES];
|
||||
void (*on_message)(dat_peer_t *peer, const uint8_t *msg, size_t len);
|
||||
} datnet_t;
|
||||
|
||||
int datnet_init();
|
||||
int datnet_bind();
|
||||
int datnet_poll();
|
||||
int datnet_send();
|
||||
int datnet_close(datnet_t *net);
|
||||
|
||||
#endif /* DAT_NET_H */
|
||||
#endif
|
||||
@@ -0,0 +1,48 @@
|
||||
#ifndef DAT_PATHS_H
|
||||
#define DAT_PATHS_H
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
/* Return the user's home directory across POSIX shells and native Windows
|
||||
* launches. Windows GUI starts commonly have USERPROFILE but no HOME. */
|
||||
static inline const char *dat_home_directory(void)
|
||||
{
|
||||
const char *home = getenv("HOME");
|
||||
if (home && *home) return home;
|
||||
#ifdef _WIN32
|
||||
home = getenv("USERPROFILE");
|
||||
if (home && *home) return home;
|
||||
{
|
||||
const char *drive = getenv("HOMEDRIVE");
|
||||
const char *path = getenv("HOMEPATH");
|
||||
static char combined[1024];
|
||||
int n;
|
||||
if (!drive || !*drive || !path || !*path) return NULL;
|
||||
n = snprintf(combined, sizeof(combined), "%s%s", drive, path);
|
||||
return n >= 0 && (size_t)n < sizeof(combined) ? combined : NULL;
|
||||
}
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* POSIX rename replaces an existing file; Windows rename does not. These
|
||||
* state files are written to a sibling temporary file before replacement. */
|
||||
static inline int dat_replace_file(const char *temporary, const char *destination)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (MoveFileExA(temporary, destination,
|
||||
MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH)) return 0;
|
||||
errno = EIO;
|
||||
return -1;
|
||||
#else
|
||||
return rename(temporary, destination);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,16 @@
|
||||
#ifndef DAT_S7_H
|
||||
#define DAT_S7_H
|
||||
#include "s7.h"
|
||||
#include "dat.h"
|
||||
typedef struct dat_scheme_runtime {
|
||||
s7_scheme *scheme;
|
||||
} dat_scheme_runtime_t;
|
||||
|
||||
int dat_s7_init(s7_scheme *scheme);
|
||||
int dat_scheme_runtime_init(dat_scheme_runtime_t *runtime);
|
||||
void dat_scheme_runtime_close(dat_scheme_runtime_t *runtime);
|
||||
int dat_scheme_write_archive_info(s7_scheme *scheme, const char *root,
|
||||
const dat_archive_t *archive,
|
||||
const char *title, const char *description,
|
||||
int replace);
|
||||
#endif
|
||||
@@ -0,0 +1,151 @@
|
||||
#ifndef DAT_SESSION_H
|
||||
#define DAT_SESSION_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "cesspool.h"
|
||||
#include "dat.h"
|
||||
#include "dat_wire.h"
|
||||
#include "sleep_feed.h"
|
||||
#include "sleep_replication.h"
|
||||
|
||||
#define DAT_SESSION_MAX_PEERS 64u
|
||||
#define DAT_SESSION_CAP_METADATA_ONLY (UINT64_C(1) << 63)
|
||||
|
||||
enum dat_session_state {
|
||||
DAT_SESSION_CLOSED = 0,
|
||||
DAT_SESSION_OPEN = 1,
|
||||
DAT_SESSION_DISCOVERING = 2,
|
||||
DAT_SESSION_ACTIVE = 3,
|
||||
DAT_SESSION_CLOSING = 4,
|
||||
DAT_SESSION_FAILED = 5
|
||||
};
|
||||
|
||||
enum dat_session_peer_state {
|
||||
DAT_SESSION_PEER_DISCOVERED = 1,
|
||||
DAT_SESSION_PEER_SECURE = 2,
|
||||
DAT_SESSION_PEER_READY = 3,
|
||||
DAT_SESSION_PEER_CLOSED = 4
|
||||
};
|
||||
|
||||
enum dat_session_feed {
|
||||
DAT_SESSION_METADATA = 0,
|
||||
DAT_SESSION_CONTENT = 1,
|
||||
DAT_SESSION_FEED_COUNT = 2
|
||||
};
|
||||
|
||||
typedef struct dat_session_peer {
|
||||
uint8_t peer_id[DAT_PEER_ID_BYTES];
|
||||
uint8_t tx_nonce[24];
|
||||
uint8_t rx_nonce[24];
|
||||
uint8_t *rx_buffer;
|
||||
size_t rx_buffer_len;
|
||||
size_t rx_buffer_capacity;
|
||||
uint64_t tx_offset;
|
||||
uint64_t rx_offset;
|
||||
uint8_t remote_feed_mask;
|
||||
uint8_t local_feed_mask;
|
||||
uint8_t remote_content_discovery[32];
|
||||
int remote_content_pending;
|
||||
dat_peer_t address;
|
||||
uint64_t capabilities;
|
||||
uint64_t payload_bytes_sent;
|
||||
uint64_t payload_bytes_received;
|
||||
int state;
|
||||
int transport_authenticated;
|
||||
int paused;
|
||||
int tx_stream_encrypted;
|
||||
int rx_stream_encrypted;
|
||||
sleep_replication_t replication[DAT_SESSION_FEED_COUNT];
|
||||
} dat_session_peer_t;
|
||||
|
||||
struct dat_session;
|
||||
typedef int (*dat_session_send_fn)(void *context,
|
||||
const uint8_t peer_id[DAT_PEER_ID_BYTES],
|
||||
const uint8_t *frame, size_t frame_len);
|
||||
typedef int (*dat_session_request_fn)(void *context,
|
||||
const uint8_t peer_id[DAT_PEER_ID_BYTES],
|
||||
enum dat_session_feed feed,
|
||||
const dat_request_t *request);
|
||||
/* Called when discovery yields a peer; establish an authenticated transport,
|
||||
* then report success with dat_session_peer_secure(). */
|
||||
typedef void (*dat_session_peer_fn)(void *context,
|
||||
const dat_session_peer_t *peer);
|
||||
typedef int (*dat_session_poll_fn)(void *context, int timeout_ms);
|
||||
|
||||
/*
|
||||
* Session protocol state is separate from connection establishment. In the
|
||||
* Cesspool path, call peer_secure only after the authenticated transport has
|
||||
* bound this peer ID to the topic. In legacy Hypercore V6 mode, call it once
|
||||
* the discovered TCP/uTP stream is connected; V6 performs its feed-key stream
|
||||
* encryption inside the protocol itself.
|
||||
*/
|
||||
typedef struct dat_session {
|
||||
int state;
|
||||
int announcing;
|
||||
int looking_up;
|
||||
uint16_t port;
|
||||
uint8_t archive_key[DAT_KEY_BYTES];
|
||||
uint8_t discovery_topic[CESSPOOL_TOPIC_BYTES];
|
||||
uint8_t peer_id[DAT_PEER_ID_BYTES];
|
||||
uint8_t feed_keys[DAT_SESSION_FEED_COUNT][DAT_KEY_BYTES];
|
||||
int content_key_known;
|
||||
cesspool_t *cesspool;
|
||||
sleep_feed_t *feeds[DAT_SESSION_FEED_COUNT];
|
||||
dat_session_peer_t peers[DAT_SESSION_MAX_PEERS];
|
||||
size_t peer_count;
|
||||
dat_session_send_fn send;
|
||||
dat_session_request_fn on_request;
|
||||
dat_session_peer_fn on_peer;
|
||||
void *peer_context;
|
||||
dat_session_poll_fn poll_transport;
|
||||
void *poll_context;
|
||||
void *context;
|
||||
} dat_session_t;
|
||||
|
||||
int dat_session_init(dat_session_t *session, cesspool_t *cesspool,
|
||||
const uint8_t archive_key[DAT_KEY_BYTES],
|
||||
const uint8_t peer_id[DAT_PEER_ID_BYTES], uint16_t port,
|
||||
sleep_feed_t *metadata_feed,
|
||||
const uint8_t metadata_key[DAT_KEY_BYTES],
|
||||
sleep_feed_t *content_feed,
|
||||
const uint8_t content_key[DAT_KEY_BYTES],
|
||||
dat_session_send_fn send, void *context);
|
||||
int dat_session_start(dat_session_t *session, int announce, int lookup);
|
||||
int dat_session_set_peer_callback(dat_session_t *session,
|
||||
dat_session_peer_fn callback, void *context);
|
||||
int dat_session_set_transport_poll(dat_session_t *session,
|
||||
dat_session_poll_fn poll, void *context);
|
||||
int dat_session_peer_discovered(dat_session_t *session,
|
||||
const cesspool_peer_t *discovered_peer);
|
||||
int dat_session_peer_secure(dat_session_t *session,
|
||||
const uint8_t peer_id[DAT_PEER_ID_BYTES],
|
||||
int transport_authenticated);
|
||||
/* For a metadata-only archive import, install the content key learned from
|
||||
* the verified metadata header and announce that feed to connected peers. */
|
||||
int dat_session_set_content_key(dat_session_t *session,
|
||||
const uint8_t content_key[DAT_KEY_BYTES]);
|
||||
int dat_session_expect_content_key(dat_session_t *session);
|
||||
int dat_session_peer_down(dat_session_t *session,
|
||||
const uint8_t peer_id[DAT_PEER_ID_BYTES]);
|
||||
/* Pause this client's incoming block requests without dropping the peer. */
|
||||
int dat_session_peer_pause(dat_session_t *session,
|
||||
const uint8_t peer_id[DAT_PEER_ID_BYTES], int paused);
|
||||
/* Accept arbitrary transport chunks. Partial and coalesced wire frames are buffered. */
|
||||
int dat_session_receive(dat_session_t *session,
|
||||
const uint8_t peer_id[DAT_PEER_ID_BYTES],
|
||||
const uint8_t *frame, size_t frame_len);
|
||||
int dat_session_request_block(dat_session_t *session,
|
||||
const uint8_t peer_id[DAT_PEER_ID_BYTES],
|
||||
enum dat_session_feed feed, uint64_t index,
|
||||
uint64_t bytes);
|
||||
int dat_session_send_block(dat_session_t *session,
|
||||
const uint8_t peer_id[DAT_PEER_ID_BYTES],
|
||||
enum dat_session_feed feed, uint64_t index);
|
||||
int dat_session_tick(dat_session_t *session, uint64_t now_ms);
|
||||
int dat_session_poll(dat_session_t *session, int timeout_ms, uint64_t now_ms);
|
||||
int dat_session_close(dat_session_t *session);
|
||||
dat_session_peer_t *dat_session_find_peer(dat_session_t *session,
|
||||
const uint8_t peer_id[DAT_PEER_ID_BYTES]);
|
||||
|
||||
#endif /* DAT_SESSION_H */
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef DAT_SOCKET_H
|
||||
#define DAT_SOCKET_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
typedef SOCKET dat_socket_t;
|
||||
#define DAT_INVALID_SOCKET INVALID_SOCKET
|
||||
#else
|
||||
#include <sys/socket.h>
|
||||
typedef int dat_socket_t;
|
||||
#define DAT_INVALID_SOCKET (-1)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
#ifndef DAT_WIRE_H
|
||||
#define DAT_WIRE_H
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
enum dat_message_type {
|
||||
DAT_MSG_FEED = 0,
|
||||
DAT_MSG_HANDSHAKE = 1,
|
||||
DAT_MSG_INFO = 2,
|
||||
DAT_MSG_HAVE = 3,
|
||||
DAT_MSG_UNHAVE = 4,
|
||||
DAT_MSG_WANT = 5,
|
||||
DAT_MSG_UNWANT = 6,
|
||||
DAT_MSG_REQUEST = 7,
|
||||
DAT_MSG_CANCEL = 8,
|
||||
DAT_MSG_DATA = 9,
|
||||
DAT_MSG_EXTENSION = 15
|
||||
};
|
||||
|
||||
typedef struct dat_feed_open {
|
||||
uint8_t discovery_key[32];
|
||||
uint8_t nonce[24];
|
||||
int has_nonce;
|
||||
} dat_feed_open_t;
|
||||
|
||||
typedef struct dat_wire_message {
|
||||
uint64_t channel;
|
||||
uint64_t type;
|
||||
const uint8_t *payload;
|
||||
size_t payload_len;
|
||||
} dat_wire_message_t;
|
||||
|
||||
#define DAT_PROTOCOL_BYTES 32u
|
||||
#define DAT_PEER_ID_BYTES 32u
|
||||
#ifndef DAT_NETWORK_PROTOCOL
|
||||
#define DAT_NETWORK_PROTOCOL "cesspool"
|
||||
#endif
|
||||
/*
|
||||
* The exact protocol token lives in the repository-root NETWORK_PROTOCOL
|
||||
* file. The Cesspool handshake carries it in `userData`; legacy Hypercore V6
|
||||
* omits that application-owned field and uses the token to select its
|
||||
* discovery namespace and wire mode. This checkout defaults to `cesspool`.
|
||||
*/
|
||||
typedef struct dat_handshake {
|
||||
uint8_t protocol[DAT_PROTOCOL_BYTES];
|
||||
uint8_t peer_id[DAT_PEER_ID_BYTES];
|
||||
uint64_t capabilities;
|
||||
int has_peer_id;
|
||||
} dat_handshake_t;
|
||||
int dat_handshake_init(dat_handshake_t *handshake,
|
||||
const uint8_t peer_id[DAT_PEER_ID_BYTES],
|
||||
uint64_t capabilities);
|
||||
int dat_handshake_protocol_matches(const dat_handshake_t *handshake);
|
||||
typedef struct dat_range { uint64_t start; uint64_t length; } dat_range_t;
|
||||
typedef struct dat_info { uint8_t uploading; uint8_t downloading; } dat_info_t;
|
||||
typedef struct dat_request { uint64_t index; uint64_t bytes; uint8_t want_hash; uint8_t want_nodes; } dat_request_t;
|
||||
#define DAT_DATA_MAX_NODES 128u
|
||||
typedef struct dat_data_node {
|
||||
uint64_t index;
|
||||
uint64_t length;
|
||||
uint8_t hash[32];
|
||||
} dat_data_node_t;
|
||||
typedef struct dat_data {
|
||||
uint64_t index;
|
||||
const uint8_t *value;
|
||||
size_t value_len;
|
||||
const uint8_t *proof;
|
||||
size_t proof_len;
|
||||
dat_data_node_t nodes[DAT_DATA_MAX_NODES];
|
||||
size_t node_count;
|
||||
uint8_t signature[64];
|
||||
int has_signature;
|
||||
} dat_data_t;
|
||||
typedef struct dat_cancel { uint64_t index; } dat_cancel_t;
|
||||
typedef struct dat_extension {
|
||||
uint64_t id;
|
||||
const uint8_t *message;
|
||||
size_t message_len;
|
||||
} dat_extension_t;
|
||||
|
||||
/* Hypercore frames are length-prefixed; headers pack channel and type. */
|
||||
int dat_wire_encode(const dat_wire_message_t *message, uint8_t *out,
|
||||
size_t capacity, size_t *written);
|
||||
int dat_wire_decode(dat_wire_message_t *message, const uint8_t *input,
|
||||
size_t input_len, size_t *consumed);
|
||||
int dat_handshake_encode(const dat_handshake_t *handshake, uint8_t *out,
|
||||
size_t capacity, size_t *written);
|
||||
int dat_handshake_decode(dat_handshake_t *handshake, const uint8_t *input,
|
||||
size_t input_len);
|
||||
int dat_feed_open_encode(const dat_feed_open_t *feed, uint8_t *out,
|
||||
size_t capacity, size_t *written);
|
||||
int dat_feed_open_decode(dat_feed_open_t *feed, const uint8_t *input,
|
||||
size_t input_len);
|
||||
int dat_range_encode(const dat_range_t *range, uint8_t *out, size_t capacity, size_t *written);
|
||||
int dat_range_decode(dat_range_t *range, const uint8_t *input, size_t input_len);
|
||||
/* WANT omits length to mean through the current end of a non-live feed. */
|
||||
int dat_want_decode(dat_range_t *range, const uint8_t *input, size_t input_len,
|
||||
uint64_t feed_length);
|
||||
int dat_info_encode(const dat_info_t *info, uint8_t *out, size_t capacity,
|
||||
size_t *written);
|
||||
int dat_info_decode(dat_info_t *info, const uint8_t *input, size_t input_len);
|
||||
int dat_request_encode(const dat_request_t *request, uint8_t *out, size_t capacity, size_t *written);
|
||||
int dat_request_decode(dat_request_t *request, const uint8_t *input, size_t input_len);
|
||||
int dat_data_encode(const dat_data_t *data, uint8_t *out, size_t capacity, size_t *written);
|
||||
int dat_data_decode(dat_data_t *data, const uint8_t *input, size_t input_len);
|
||||
int dat_cancel_encode(const dat_cancel_t *cancel, uint8_t *out, size_t capacity, size_t *written);
|
||||
int dat_cancel_decode(dat_cancel_t *cancel, const uint8_t *input, size_t input_len);
|
||||
int dat_extension_encode(const dat_extension_t *extension, uint8_t *out, size_t capacity, size_t *written);
|
||||
int dat_extension_decode(dat_extension_t *extension, const uint8_t *input, size_t input_len);
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
#ifndef DATGPT_ERRNO_COMPAT_H
|
||||
#define DATGPT_ERRNO_COMPAT_H
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
/* EKEYREJECTED is a Linux extension. Keep the key-authentication failure
|
||||
* portable while preserving a useful access-denied error on other hosts. */
|
||||
#ifndef EKEYREJECTED
|
||||
#define EKEYREJECTED EACCES
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+27
-4
@@ -11,7 +11,7 @@ content.key
|
||||
content.signatures
|
||||
content.bitfield
|
||||
content.tree*/
|
||||
#include "key.h"
|
||||
#include "keys.h"
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
// test
|
||||
@@ -21,8 +21,14 @@ content.tree*/
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int sleep_init(const char *root);
|
||||
|
||||
#define SLEEP_HEADER_SIZE 32u
|
||||
|
||||
#define SLEEP_MAGIC_BITFIELD 0x05025700u
|
||||
#define SLEEP_MAGIC_SIGNATURE 0x05025701u
|
||||
#define SLEEP_MAGIC_TREE 0x05025702u
|
||||
|
||||
// TODO MAGIC_BITFIELD, MAGIC_SIG, MAGIC_TREE
|
||||
|
||||
#define SLEEP_ALGO_BLAKE2B "BLAKE2b"
|
||||
@@ -30,7 +36,7 @@ extern "C" {
|
||||
|
||||
#define SLEEP_TREE_ENTRY_SIZE 40u
|
||||
#define SLEEP_SIG_ENTRY_SIZE 64u
|
||||
#define SLEEP_BITFIELD_ENTRY_SIZE 3328u
|
||||
#define SLEEP_BITFIELD_ENTRY_SIZE 3584u
|
||||
|
||||
enum sleep_hash_type {
|
||||
SLEEP_HASH_LEAF = 0,
|
||||
@@ -69,11 +75,12 @@ typedef struct SLEEP_PACKED sleep_sig_entry {
|
||||
} sleep_sig_entry_t;
|
||||
// TODO assert
|
||||
|
||||
// 3328 bytes: tree[2048] + data[1024] + index[256]
|
||||
// 3584-byte historical record. The final 256 bytes are opaque for now.
|
||||
typedef struct SLEEP_PACKED sleep_bitfield_entry {
|
||||
uint8_t tree[2048];
|
||||
uint8_t data[1024];
|
||||
uint8_t tree[2048];
|
||||
uint8_t index[256];
|
||||
uint8_t reserved[256];
|
||||
} sleep_bitfield_entry_t;
|
||||
// TODO DOTO ODOT assert it
|
||||
|
||||
@@ -97,6 +104,22 @@ int sleep_compute_discovery_key(const uint8_t pubkey[32], uint8_t out32[32]);
|
||||
#endif /* SLEEP_SALT */
|
||||
|
||||
// function decs
|
||||
uint64_t sleep_tree_index(uint64_t depth, uint64_t offset);
|
||||
uint64_t sleep_tree_depth(uint64_t index);
|
||||
uint64_t sleep_tree_offset(uint64_t index, uint64_t depth);
|
||||
uint64_t sleep_tree_parent(uint64_t index);
|
||||
int sleep_tree_left_child(uint64_t index, uint64_t *out);
|
||||
int sleep_tree_right_child(uint64_t index, uint64_t *out);
|
||||
int sleep_tree_sibling(uint64_t index, uint64_t *out);
|
||||
uint64_t sleep_tree_left_span(uint64_t index);
|
||||
uint64_t sleep_tree_right_span(uint64_t index);
|
||||
void sleep_tree_spans(uint64_t index, uint64_t *left, uint64_t *right);
|
||||
size_t sleep_tree_count(uint64_t index);
|
||||
size_t sleep_tree_count_leaves(uint64_t index);
|
||||
size_t sleep_tree_full_roots(uint64_t index, uint64_t *out, size_t capacity);
|
||||
int sleep_tree_hash_block(const uint8_t *data, size_t len, uint8_t out_hash[32]);
|
||||
int sleep_tree_hash_parent(const uint8_t left[32], const uint8_t right[32],
|
||||
uint64_t length, uint8_t out_hash[32]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
#ifndef SLEEP_BITFIELD_H
|
||||
#define SLEEP_BITFIELD_H
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define SLEEP_BITFIELD_DATA_BYTES 1024u
|
||||
#define SLEEP_BITFIELD_TREE_BYTES 2048u
|
||||
#define SLEEP_BITFIELD_INDEX_BYTES 256u
|
||||
#define SLEEP_BITFIELD_RESERVED_BYTES 256u
|
||||
|
||||
typedef struct sleep_bitfield {
|
||||
uint8_t data[SLEEP_BITFIELD_DATA_BYTES];
|
||||
uint8_t tree[SLEEP_BITFIELD_TREE_BYTES];
|
||||
uint8_t index[SLEEP_BITFIELD_INDEX_BYTES];
|
||||
uint8_t reserved[SLEEP_BITFIELD_RESERVED_BYTES];
|
||||
} sleep_bitfield_t;
|
||||
|
||||
void sleep_bitfield_clear(sleep_bitfield_t *field);
|
||||
int sleep_bitfield_get_data(const sleep_bitfield_t *field, size_t bit);
|
||||
int sleep_bitfield_get_tree(const sleep_bitfield_t *field, size_t bit);
|
||||
int sleep_bitfield_set_data(sleep_bitfield_t *field, size_t bit, int present);
|
||||
int sleep_bitfield_set_tree(sleep_bitfield_t *field, size_t bit, int present);
|
||||
void sleep_bitfield_reindex(sleep_bitfield_t *field);
|
||||
size_t sleep_bitfield_next_data(const sleep_bitfield_t *field, size_t start, int present);
|
||||
int sleep_bitfield_encode(const sleep_bitfield_t *field, uint8_t *out, size_t capacity);
|
||||
int sleep_bitfield_decode(sleep_bitfield_t *field, const uint8_t *input, size_t length);
|
||||
#endif
|
||||
+13
-6
@@ -4,19 +4,26 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "keys.h"
|
||||
//#include "sleep.h"
|
||||
#define SLEEP_ROOT_RECORD_BYTES 48u
|
||||
|
||||
int sleep_crypto_init(void);
|
||||
int sleep_stream_xsalsa20_xor(uint8_t *out, const uint8_t *in, size_t length,
|
||||
const uint8_t nonce[24], const uint8_t key[32],
|
||||
uint64_t stream_offset);
|
||||
int sleep_gen_keypair(sleep_keypair_t *kp);
|
||||
int sleep_save_pubkey(const char *path, const uint8_t pubkey[SLEEP_PUBLIC_KEY_BYTES]);
|
||||
int sleep_load_pubkey(const char *path, uint8_t pubkey[SLEEP_PUBLIC_KEY_BYTES]);
|
||||
int sleep_save_pubkey(const char *path, const uint8_t pubkey[SLEEP_PUB_KEY_BYTES]);
|
||||
int sleep_load_pubkey(const char *path, uint8_t pubkey[SLEEP_PUB_KEY_BYTES]);
|
||||
int sleep_save_keypair(const char *path, const sleep_keypair_t *keypair);
|
||||
int sleep_load_keypair(const char *path, sleep_keypair_t *keypair);
|
||||
|
||||
int sleep_blake2b(uint8_t out[SLEEP_BLAKE2B_BYTES], const uint8_t *in, size_t inlen);
|
||||
|
||||
int sleep_sign(uint8_t sig[SLEEP_BLAKE2B_BYTES], const uint8_t *msg, size_t msglen, const sleep_keypair_t *kp);
|
||||
int sleep_sign(uint8_t sig[SLEEP_SIGNATURE_BYTES], const uint8_t *msg, size_t msglen, const sleep_keypair_t *kp);
|
||||
|
||||
int sleep_verify(const uint8_t sig[SLEEP_SIGNATURE_BYTES], const uint8_t *msg, size_t msglen, const uint8_t pubkey[SLEEP_PUBLIC_KEY_BYTES]);
|
||||
int sleep_verify(const uint8_t sig[SLEEP_SIGNATURE_BYTES], const uint8_t *msg, size_t msglen, const uint8_t pubkey[SLEEP_PUB_KEY_BYTES]);
|
||||
|
||||
int sleep_sign_roots(uint8_t sig[SLEEP_SIGNATURE_BYTES], const uint8_t *roots, size_t nroots, const uint64_t *indices, const uint64_t *lengths, const sleep_keypair_t *kp);
|
||||
|
||||
int sleep_verify_roots(const uint8_t sig[SLEEP_SIGNATURE_BYTES], const uint8_t *roots, size_t nroots, const uint64_t *indices, const uint64_t *lengths, const uint8_t pub[SLEEP_PUBLIC_KEY_BYTES]);
|
||||
int sleep_verify_roots(const uint8_t sig[SLEEP_SIGNATURE_BYTES], const uint8_t *roots, size_t nroots, const uint64_t *indices, const uint64_t *lengths, const uint8_t pub[SLEEP_PUB_KEY_BYTES]);
|
||||
|
||||
#endif /* SLEEP_CRYPTO_H */
|
||||
@@ -0,0 +1,43 @@
|
||||
#ifndef SLEEP_FEED_H
|
||||
#define SLEEP_FEED_H
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "keys.h"
|
||||
|
||||
typedef struct sleep_feed {
|
||||
char directory[1024];
|
||||
char name[64];
|
||||
uint8_t **blocks;
|
||||
size_t *lengths;
|
||||
uint8_t **proofs;
|
||||
size_t *proof_lengths;
|
||||
size_t length;
|
||||
size_t capacity;
|
||||
sleep_keypair_t keypair;
|
||||
int writable;
|
||||
int dirty;
|
||||
int remote_only;
|
||||
int persist_remote;
|
||||
} sleep_feed_t;
|
||||
|
||||
int sleep_feed_open(sleep_feed_t *feed, const char *directory, const char *name,
|
||||
const sleep_keypair_t *keypair);
|
||||
/* Opens an in-memory, read-only feed replica using only its public key. */
|
||||
int sleep_feed_open_remote(sleep_feed_t *feed, const char *directory,
|
||||
const char *name, const uint8_t public_key[32]);
|
||||
/* Merge verified cached remote blocks and persist subsequent received blocks. */
|
||||
int sleep_feed_load_remote(sleep_feed_t *feed, const uint8_t public_key[32]);
|
||||
size_t sleep_feed_length(const sleep_feed_t *feed);
|
||||
int sleep_feed_read(const sleep_feed_t *feed, size_t index, uint8_t **data, size_t *length);
|
||||
int sleep_feed_append(sleep_feed_t *feed, const uint8_t *data, size_t length);
|
||||
/* Keeps already verified remote blocks and proofs in this session's memory. */
|
||||
int sleep_feed_append_remote(sleep_feed_t *feed, size_t index,
|
||||
const uint8_t *data, size_t length,
|
||||
const uint8_t *proof, size_t proof_length);
|
||||
int sleep_feed_truncate(sleep_feed_t *feed, size_t length);
|
||||
int sleep_feed_has(const sleep_feed_t *feed, size_t index);
|
||||
int sleep_feed_byte_offset(const sleep_feed_t *feed, size_t index,
|
||||
uint64_t *offset);
|
||||
int sleep_feed_flush(sleep_feed_t *feed);
|
||||
void sleep_feed_close(sleep_feed_t *feed);
|
||||
#endif
|
||||
@@ -0,0 +1,43 @@
|
||||
#ifndef SLEEP_PROOF_H
|
||||
#define SLEEP_PROOF_H
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "sleep_feed.h"
|
||||
|
||||
#define SLEEP_PROOF_HASH_BYTES 32u
|
||||
#define SLEEP_PROOF_MAX_NODES 64u
|
||||
typedef struct sleep_proof_node {
|
||||
uint64_t index;
|
||||
uint64_t length;
|
||||
uint8_t hash[SLEEP_PROOF_HASH_BYTES];
|
||||
} sleep_proof_node_t;
|
||||
typedef struct sleep_proof {
|
||||
uint64_t block;
|
||||
uint64_t block_length;
|
||||
uint8_t block_hash[SLEEP_PROOF_HASH_BYTES];
|
||||
sleep_proof_node_t nodes[SLEEP_PROOF_MAX_NODES];
|
||||
size_t node_count;
|
||||
sleep_proof_node_t roots[SLEEP_PROOF_MAX_NODES];
|
||||
size_t root_count;
|
||||
uint8_t signature[64];
|
||||
int has_signature;
|
||||
} sleep_proof_t;
|
||||
|
||||
void sleep_proof_init(sleep_proof_t *proof, uint64_t block);
|
||||
int sleep_proof_add_node(sleep_proof_t *proof, uint64_t index,
|
||||
uint64_t length, const uint8_t hash[32]);
|
||||
int sleep_proof_add_root(sleep_proof_t *proof, uint64_t index,
|
||||
uint64_t length, const uint8_t hash[32]);
|
||||
int sleep_proof_create(const sleep_feed_t *feed, uint64_t block,
|
||||
sleep_proof_t *proof);
|
||||
int sleep_proof_from_nodes(uint64_t block, const uint8_t *value,
|
||||
size_t value_len, const sleep_proof_node_t *nodes,
|
||||
size_t node_count, const uint8_t signature[64],
|
||||
uint64_t feed_length, sleep_proof_t *proof);
|
||||
int sleep_proof_encode(const sleep_proof_t *proof, uint8_t *out,
|
||||
size_t capacity, size_t *written);
|
||||
int sleep_proof_decode(sleep_proof_t *proof, const uint8_t *input,
|
||||
size_t input_len);
|
||||
int sleep_proof_verify(const sleep_proof_t *proof, const uint8_t *block,
|
||||
size_t block_len, const uint8_t public_key[32]);
|
||||
#endif
|
||||
@@ -0,0 +1,26 @@
|
||||
#ifndef SLEEP_PROTO_H
|
||||
#define SLEEP_PROTO_H
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#define SLEEP_PROTO_KEY_BYTES 32u
|
||||
typedef struct sleep_metadata_header { char type[32]; uint8_t content[32]; size_t content_len; } sleep_metadata_header_t;
|
||||
enum sleep_entry_type { SLEEP_ENTRY_FILE=1, SLEEP_ENTRY_DIRECTORY=2, SLEEP_ENTRY_SYMLINK=3, SLEEP_ENTRY_DELETE=4 };
|
||||
typedef struct sleep_metadata_entry {
|
||||
char path[1024];
|
||||
uint32_t type;
|
||||
uint32_t mode;
|
||||
uint64_t size;
|
||||
uint64_t mtime;
|
||||
uint64_t block_offset;
|
||||
uint64_t block_count;
|
||||
char linkname[1024];
|
||||
} sleep_metadata_entry_t;
|
||||
size_t sleep_varint_size(uint64_t value);
|
||||
int sleep_varint_encode(uint64_t value, uint8_t *out, size_t capacity, size_t *written);
|
||||
int sleep_varint_decode(const uint8_t *input, size_t input_len, uint64_t *value, size_t *consumed);
|
||||
int sleep_metadata_header_encode(const sleep_metadata_header_t *header, uint8_t *out, size_t capacity, size_t *written);
|
||||
int sleep_metadata_header_decode(sleep_metadata_header_t *header, const uint8_t *input, size_t input_len);
|
||||
int sleep_write_metadata_header(const char *path, const uint8_t content_pubkey[32]);
|
||||
int sleep_metadata_entry_encode(const sleep_metadata_entry_t *entry, uint8_t *out, size_t capacity, size_t *written);
|
||||
int sleep_metadata_entry_decode(sleep_metadata_entry_t *entry, const uint8_t *input, size_t input_len);
|
||||
#endif
|
||||
@@ -0,0 +1,44 @@
|
||||
#ifndef SLEEP_REPLICATION_H
|
||||
#define SLEEP_REPLICATION_H
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "sleep_feed.h"
|
||||
#include "sleep_bitfield.h"
|
||||
#include "sleep_proof.h"
|
||||
|
||||
#define SLEEP_REPLICATION_QUEUE 128u
|
||||
typedef struct sleep_replication_request { uint64_t index; uint64_t bytes; int hash; int nodes; } sleep_replication_request_t;
|
||||
typedef struct sleep_replication {
|
||||
sleep_feed_t *feed;
|
||||
uint64_t channel;
|
||||
uint64_t remote_length;
|
||||
sleep_bitfield_t remote_bitfield;
|
||||
sleep_replication_request_t requests[SLEEP_REPLICATION_QUEUE];
|
||||
size_t request_head, request_count;
|
||||
int live, uploading, downloading;
|
||||
} sleep_replication_t;
|
||||
|
||||
int sleep_replication_init(sleep_replication_t *replication,
|
||||
sleep_feed_t *feed, uint64_t channel);
|
||||
int sleep_replication_have(sleep_replication_t *replication,
|
||||
uint64_t start, uint64_t length);
|
||||
int sleep_replication_unhave(sleep_replication_t *replication,
|
||||
uint64_t start, uint64_t length);
|
||||
int sleep_replication_want(sleep_replication_t *replication,
|
||||
uint64_t start, uint64_t length);
|
||||
int sleep_replication_request(sleep_replication_t *replication,
|
||||
const sleep_replication_request_t *request);
|
||||
int sleep_replication_next(sleep_replication_t *replication,
|
||||
sleep_replication_request_t *request);
|
||||
int sleep_replication_complete(sleep_replication_t *replication,
|
||||
uint64_t index);
|
||||
int sleep_replication_is_requested(const sleep_replication_t *replication,
|
||||
uint64_t index);
|
||||
int sleep_replication_unwant(sleep_replication_t *replication,
|
||||
uint64_t start, uint64_t length);
|
||||
void sleep_replication_clear_requests(sleep_replication_t *replication);
|
||||
int sleep_replication_receive(sleep_replication_t *replication,
|
||||
const uint8_t *block, size_t block_len,
|
||||
const sleep_proof_t *proof,
|
||||
const uint8_t feed_public_key[32]);
|
||||
#endif
|
||||
@@ -0,0 +1,39 @@
|
||||
#ifndef SLEEP_UTP_H
|
||||
#define SLEEP_UTP_H
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "dat_socket.h"
|
||||
|
||||
#define SLEEP_UTP_MTU 1200u
|
||||
#define SLEEP_UTP_WINDOW 64u
|
||||
enum sleep_utp_state { SLEEP_UTP_CLOSED, SLEEP_UTP_SYN_SENT, SLEEP_UTP_SYN_RECV, SLEEP_UTP_CONNECTED, SLEEP_UTP_FIN_SENT, SLEEP_UTP_RESET };
|
||||
enum sleep_utp_packet_type { SLEEP_UTP_DATA, SLEEP_UTP_FIN, SLEEP_UTP_STATE, SLEEP_UTP_RESET_PACKET, SLEEP_UTP_SYN };
|
||||
typedef struct sleep_utp_packet { uint8_t type, version; uint16_t connection_id; uint32_t timestamp, timestamp_diff, window_size; uint16_t sequence, acknowledgement; uint32_t selective_ack; int has_selective_ack; const uint8_t *payload; size_t payload_len; } sleep_utp_packet_t;
|
||||
typedef struct sleep_utp_slot { uint16_t sequence; uint8_t data[SLEEP_UTP_MTU]; size_t length; uint64_t sent_at; unsigned retries; int used; } sleep_utp_slot_t;
|
||||
typedef struct sleep_utp {
|
||||
dat_socket_t socket;
|
||||
struct sockaddr_storage remote;
|
||||
socklen_t remote_len;
|
||||
uint16_t send_id, receive_id, sequence, acknowledgement;
|
||||
uint32_t receive_window, send_window;
|
||||
enum sleep_utp_state state;
|
||||
uint64_t retransmit_at;
|
||||
unsigned syn_retries;
|
||||
uint32_t congestion_window, slow_start_threshold;
|
||||
uint32_t round_trip_time, round_trip_variance;
|
||||
size_t bytes_in_flight;
|
||||
sleep_utp_slot_t unacked[SLEEP_UTP_WINDOW];
|
||||
sleep_utp_slot_t reorder[SLEEP_UTP_WINDOW];
|
||||
void *context;
|
||||
void (*on_data)(struct sleep_utp *, const uint8_t *, size_t);
|
||||
} sleep_utp_t;
|
||||
int sleep_utp_init(sleep_utp_t *utp, dat_socket_t udp_socket);
|
||||
int sleep_utp_connect(sleep_utp_t *utp, const struct sockaddr *remote, socklen_t remote_len);
|
||||
int sleep_utp_accept(sleep_utp_t *utp, const sleep_utp_packet_t *syn, const struct sockaddr *remote, socklen_t remote_len);
|
||||
int sleep_utp_packet_encode(const sleep_utp_packet_t *packet, uint8_t *out, size_t capacity, size_t *written);
|
||||
int sleep_utp_packet_decode(sleep_utp_packet_t *packet, const uint8_t *input, size_t input_len);
|
||||
int sleep_utp_input(sleep_utp_t *utp, const uint8_t *packet, size_t packet_len);
|
||||
int sleep_utp_send(sleep_utp_t *utp, const uint8_t *data, size_t length);
|
||||
int sleep_utp_tick(sleep_utp_t *utp, uint64_t now_ms);
|
||||
int sleep_utp_close(sleep_utp_t *utp);
|
||||
#endif
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef SLEEP_VERIFY_H
|
||||
#define SLEEP_VERIFY_H
|
||||
|
||||
int sleep_verify_dat(const char *dat_dir);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef SLEEP_WRITER_H
|
||||
#define SLEEP_WRITER_H
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "sleep.h"
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
int sleep_write_feed(const char *feed_dir,
|
||||
const char *feed_name,
|
||||
const uint8_t *const *blocks,
|
||||
const size_t *lengths,
|
||||
size_t nblocks,
|
||||
const sleep_keypair_t *keypair);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,80 @@
|
||||
#ifndef DATGPT_WIN_COMPAT_H
|
||||
#define DATGPT_WIN_COMPAT_H
|
||||
|
||||
/* Small POSIX spellings used by the shared C sources on native Windows. */
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
#include <direct.h>
|
||||
#include <process.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <windows.h>
|
||||
#ifndef mkdir
|
||||
#define mkdir(path, mode) _mkdir(path)
|
||||
#endif
|
||||
#ifndef fsync
|
||||
#define fsync(fd) _commit(fd)
|
||||
#endif
|
||||
#ifndef getpid
|
||||
#define getpid _getpid
|
||||
#endif
|
||||
#ifndef O_CLOEXEC
|
||||
#define O_CLOEXEC 0
|
||||
#endif
|
||||
#ifndef O_NOFOLLOW
|
||||
#define O_NOFOLLOW 0
|
||||
#endif
|
||||
#ifndef EKEYREJECTED
|
||||
#define EKEYREJECTED EACCES
|
||||
#endif
|
||||
#ifndef S_ISLNK
|
||||
#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
|
||||
#endif
|
||||
#ifndef S_IFLNK
|
||||
#define S_IFLNK 0120000
|
||||
#endif
|
||||
#ifndef fchmod
|
||||
#define fchmod(fd, mode) ((void)(fd), (void)(mode), 0)
|
||||
#endif
|
||||
#ifndef strcasecmp
|
||||
#define strcasecmp _stricmp
|
||||
#endif
|
||||
#ifndef strncasecmp
|
||||
#define strncasecmp _strnicmp
|
||||
#endif
|
||||
static inline char *dat_win_getenv_compat(const char *name)
|
||||
{
|
||||
char *value = getenv(name);
|
||||
if (!value && name && !strcmp(name, "HOME")) value = getenv("USERPROFILE");
|
||||
return value;
|
||||
}
|
||||
#define getenv dat_win_getenv_compat
|
||||
static inline int dat_win_lstat(const char *path, struct stat *info)
|
||||
{
|
||||
DWORD attributes;
|
||||
if (stat(path, info)) return -1;
|
||||
attributes = GetFileAttributesA(path);
|
||||
if (attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_REPARSE_POINT))
|
||||
info->st_mode = (info->st_mode & ~S_IFMT) | S_IFLNK;
|
||||
return 0;
|
||||
}
|
||||
#ifndef lstat
|
||||
#define lstat dat_win_lstat
|
||||
#endif
|
||||
static inline int dat_win_readlink(const char *path, char *target, size_t capacity)
|
||||
{ (void)path; (void)target; (void)capacity; errno = ENOTSUP; return -1; }
|
||||
static inline int dat_win_symlink(const char *target, const char *path)
|
||||
{ (void)target; (void)path; errno = ENOTSUP; return -1; }
|
||||
#ifndef readlink
|
||||
#define readlink dat_win_readlink
|
||||
#endif
|
||||
#ifndef symlink
|
||||
#define symlink dat_win_symlink
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,53 @@
|
||||
#ifndef DATGPT_WIN_DIRENT_H
|
||||
#define DATGPT_WIN_DIRENT_H
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#define NAME_MAX MAX_PATH
|
||||
typedef struct dirent { char d_name[MAX_PATH]; } struct_dirent_t;
|
||||
typedef struct dat_win_dir {
|
||||
HANDLE handle;
|
||||
WIN32_FIND_DATAA data;
|
||||
int first;
|
||||
struct dirent entry;
|
||||
} DIR;
|
||||
static DIR *dat_opendir(const char *path)
|
||||
{
|
||||
DIR *dir = (DIR *)calloc(1, sizeof(*dir));
|
||||
char pattern[MAX_PATH * 2];
|
||||
int n;
|
||||
if (!dir) return NULL;
|
||||
n = snprintf(pattern, sizeof(pattern), "%s\\*", path);
|
||||
if (n < 0 || (size_t)n >= sizeof(pattern)) { free(dir); errno = ENAMETOOLONG; return NULL; }
|
||||
dir->handle = FindFirstFileA(pattern, &dir->data);
|
||||
if (dir->handle == INVALID_HANDLE_VALUE) { free(dir); errno = ENOENT; return NULL; }
|
||||
dir->first = 1;
|
||||
return dir;
|
||||
}
|
||||
static struct dirent *dat_readdir(DIR *dir)
|
||||
{
|
||||
if (!dir) return NULL;
|
||||
if (dir->first) dir->first = 0;
|
||||
else if (!FindNextFileA(dir->handle, &dir->data)) return NULL;
|
||||
strncpy(dir->entry.d_name, dir->data.cFileName, sizeof(dir->entry.d_name) - 1);
|
||||
dir->entry.d_name[sizeof(dir->entry.d_name) - 1] = 0;
|
||||
return &dir->entry;
|
||||
}
|
||||
static int dat_closedir(DIR *dir)
|
||||
{
|
||||
int rc;
|
||||
if (!dir) { errno = EINVAL; return -1; }
|
||||
rc = FindClose(dir->handle) ? 0 : -1;
|
||||
free(dir);
|
||||
return rc;
|
||||
}
|
||||
#define opendir dat_opendir
|
||||
#define readdir dat_readdir
|
||||
#define closedir dat_closedir
|
||||
#else
|
||||
#include <dirent.h>
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,24 @@
|
||||
#ifndef DATGPT_WIN_FNMATCH_H
|
||||
#define DATGPT_WIN_FNMATCH_H
|
||||
#ifdef _WIN32
|
||||
static int dat_win_fnmatch(const char *pattern, const char *text)
|
||||
{
|
||||
while (*pattern) {
|
||||
if (*pattern == '*') {
|
||||
while (*pattern == '*') pattern++;
|
||||
if (!*pattern) return 0;
|
||||
do { if (dat_win_fnmatch(pattern, text) == 0) return 0; } while (*text++);
|
||||
return 1;
|
||||
}
|
||||
if (!*text) return 1;
|
||||
if (*pattern == '?') { pattern++; text++; continue; }
|
||||
if (*pattern != *text) return 1;
|
||||
pattern++; text++;
|
||||
}
|
||||
return *text ? 1 : 0;
|
||||
}
|
||||
#define fnmatch(pattern, text, flags) ((void)(flags), dat_win_fnmatch((pattern), (text)))
|
||||
#else
|
||||
#include <fnmatch.h>
|
||||
#endif
|
||||
#endif
|
||||
Reference in new issue
Block a user