diff --git a/pkg/c3/motes.h b/pkg/c3/motes.h index 975554e94b..69b0556cae 100644 --- a/pkg/c3/motes.h +++ b/pkg/c3/motes.h @@ -68,6 +68,7 @@ # define c3__bcts c3_s4('b','c','t','s') # define c3__bczp c3_s4('b','c','z','p') # define c3__bead c3_s4('b','e','a','d') +# define c3__beam c3_s4('b','e','a','m') # define c3__bean c3_s4('b','e','a','n') # define c3__bear c3_s4('b','e','a','r') # define c3__bede c3_s4('b','e','d','e') @@ -539,6 +540,7 @@ # define c3__head c3_s4('h','e','a','d') # define c3__heal c3_s4('h','e','a','l') # define c3__hear c3_s4('h','e','a','r') +# define c3__heer c3_s4('h','e','e','r') # define c3__hela c3_s4('h','e','l','a') # define c3__helm c3_s4('h','e','l','m') # define c3__helo c3_s4('h','e','l','o') @@ -723,6 +725,7 @@ # define c3__lt c3_s2('l','t') # define c3__lull c3_s4('l','u','l','l') # define c3__lunt c3_s4('l','u','n','t') +# define c3__m c3_s1('m') # define c3__mach c3_s4('m','a','c','h') # define c3__mack c3_s4('m','a','c','k') # define c3__made c3_s4('m','a','d','e') @@ -750,6 +753,7 @@ # define c3__memo c3_s4('m','e','m','o') # define c3__menu c3_s4('m','e','n','u') # define c3__mesh c3_s4('m','e','s','h') +# define c3__mess c3_s4('m','e','s','s') # define c3__met c3_s3('m','e','t') # define c3__meta c3_s4('m','e','t','a') # define c3__mill c3_s4('m','i','l','l') @@ -788,6 +792,7 @@ # define c3__mull c3_s4('m','u','l','l') # define c3__mung c3_s4('m','u','n','g') # define c3__mut c3_s3('m','u','t') +# define c3__mx c3_s2('m', 'x') # define c3__n c3_s1('n') # define c3__na c3_s2('n','a') # define c3__nail c3_s4('n','a','i','l') @@ -851,6 +856,8 @@ # define c3__ovum c3_s4('o','v','u','m') # define c3__p c3_s1('p') # define c3__pack c3_s4('p','a','c','k') +# define c3__pact c3_s4('p','a','c','t') +# define c3__page c3_s4('p','a','g','e') # define c3__pair c3_s4('p','a','i','r') # define c3__palm c3_s4('p','a','l','m') # define c3__palq c3_s4('p','a','l','q') @@ -1014,6 +1021,7 @@ # define c3__sell c3_s4('s','e','l','l') # define c3__semp c3_s4('s','e','m','p') # define c3__send c3_s4('s','e','n','d') +# define c3__sent c3_s4('s','e','n','t') # define c3__seq c3_s3('s','e','q') # define c3__serd c3_s4('s','e','r','d') # define c3__serf c3_s4('s','e','r','f') @@ -1321,6 +1329,9 @@ # define c3__wyp c3_s3('w','y','p') # define c3__wyrd c3_s4('w','y','r','d') # define c3__xray c3_s4('x','r','a','y') +# define c3__xmas c3_s4('x','m','a','s') +# define c3__x c3_s1('x') +# define c3__xx c3_s2('x','x') # define c3__yell c3_s4('y','e','l','l') # define c3__yelp c3_s4('y','e','l','p') # define c3__z c3_s1('z') diff --git a/pkg/noun/hashtable.c b/pkg/noun/hashtable.c index bc5d751b8c..f1f95d5737 100644 --- a/pkg/noun/hashtable.c +++ b/pkg/noun/hashtable.c @@ -270,6 +270,134 @@ u3h_put(u3p(u3h_root) har_p, u3_noun key, u3_noun val) } } +static c3_o _ch_slot_del(u3h_slot*, u3_noun, c3_w, c3_w, c3_w*); + +/* _ch_buck_del(): delete from bucket +*/ +static c3_o +_ch_buck_del(u3h_slot* sot_w, u3_noun key, c3_w *use_w) +{ + u3h_buck* hab_u = u3h_slot_to_node(*sot_w); + c3_w fin_w = hab_u->len_w; + c3_w i_w; + // + // find index of key to be deleted + // + for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) { + u3_noun kov = u3h_slot_to_noun(hab_u->sot_w[i_w]); + if ( c3y == u3r_sing(key, u3h(kov)) ) { + fin_w = i_w; + u3z(kov); + break; + } + } + + // no key found, no-op + if ( fin_w == hab_u->len_w ) { + return c3n; + } + + { + hab_u->len_w--; + u3_assert(c3y == u3h_slot_is_noun(hab_u->sot_w[fin_w])); + //u3z(u3h_slot_to_noun(hab_u->sot_w[fin_w])); + for ( i_w = fin_w; i_w < hab_u->len_w; i_w++ ) { + hab_u->sot_w[i_w] = hab_u->sot_w[i_w + 1]; + } + + *use_w -= 1; + return c3y; + } +} + +static c3_o _ch_some_del(u3h_slot*, u3_noun, c3_w, c3_w, c3_w*); + +static c3_o +_ch_slot_del(u3h_slot* sot_w, u3_noun key, c3_w lef_w, c3_w rem_w, c3_w* use_w) { + if ( c3y == u3h_slot_is_noun(*sot_w) ) { + u3_noun kev = u3h_slot_to_noun(*sot_w); + *sot_w = 0; + u3z(kev); + *use_w -= 1; + return c3y; + } else { + return _ch_some_del(sot_w, key, lef_w, rem_w, use_w); + } +} + +static c3_o +_ch_node_del(u3h_slot* sot_w, u3_noun key, c3_w lef_w, c3_w rem_w, c3_w* use_w) +{ + u3h_node* han_u = (u3h_node*) u3h_slot_to_node(*sot_w); + + c3_w bit_w, inx_w, map_w, i_w; + + lef_w -= 5; + bit_w = (rem_w >> lef_w); + rem_w = CUT_END(rem_w, lef_w); + map_w = han_u->map_w; + inx_w = _ch_popcount(CUT_END(map_w, bit_w)); + + // nothing at slot, no-op + if ( !BIT_SET(map_w, bit_w) ) { + return c3n; + } + c3_w ken_w; + u3h_slot kes_w; + u3h_slot don_w = han_u->sot_w[inx_w]; + c3_w len_w = _ch_popcount(map_w); + if ( len_w == 2 && ((ken_w = (0 == inx_w) ? 1 : 0), + (kes_w = han_u->sot_w[ken_w]), + (c3y == u3h_slot_is_noun(don_w) && c3y == u3h_slot_is_noun(kes_w))) ) { + *sot_w = kes_w; + u3z(u3h_slot_to_noun(don_w)); + *use_w -= 1; + u3a_wfree(han_u); + return c3y; + } + c3_o ret_o = _ch_slot_del(&han_u->sot_w[inx_w], key, lef_w, rem_w, use_w); + if ( c3y == ret_o && c3y == u3h_slot_is_null(han_u->sot_w[inx_w]) ) { + han_u->map_w &= ~(1 << bit_w); + for ( i_w = inx_w; i_w < len_w; i_w++ ) { + han_u->sot_w[i_w] = han_u->sot_w[i_w + 1]; + } + } + return ret_o; +} + + +static c3_o +_ch_some_del(u3h_slot* sot_w, u3_noun key, c3_w lef_w, c3_w rem_w, c3_w* use_w) +{ + if ( 0 == lef_w ) { + return _ch_buck_del(sot_w, key, use_w); + } + //u3h_node* han_u = (u3h_node*)han_v; + //if ( _ch_popcount(han_u)) + return _ch_node_del(sot_w, key, lef_w, rem_w, use_w); +} + + + +/** TODO: this has a bug where the freeing a hamt that this has been called with failes + * most likelly memroy mgmt +*/ +void +u3h_del(u3p(u3h_root) har_p, u3_noun key) +{ + u3h_root* har_u = u3to(u3h_root, har_p); + c3_w mug_w = u3r_mug(key); + c3_w inx_w = (mug_w >> 25); + c3_w rem_w = CUT_END(mug_w, 25); + u3h_slot* sot_w = &(har_u->sot_w[inx_w]); + + if ( c3y == u3h_slot_is_null(*sot_w) ) { + return; + } else { + _ch_slot_del(sot_w, key, 25, rem_w, &(har_u->use_w)); + } +} + /* _ch_uni_with(): key/value callback, put into [*wit] */ static void @@ -667,6 +795,7 @@ u3h_get(u3p(u3h_root) har_p, u3_noun key) static void _ch_free_buck(u3h_buck* hab_u) { + //fprintf(stderr, "free buck\r\n"); c3_w i_w; for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) { @@ -678,7 +807,7 @@ _ch_free_buck(u3h_buck* hab_u) /* _ch_free_node(): free node. */ static void -_ch_free_node(u3h_node* han_u, c3_w lef_w) +_ch_free_node(u3h_node* han_u, c3_w lef_w, c3_o pin_o) { c3_w len_w = _ch_popcount(han_u->map_w); c3_w i_w; @@ -687,17 +816,16 @@ _ch_free_node(u3h_node* han_u, c3_w lef_w) for ( i_w = 0; i_w < len_w; i_w++ ) { c3_w sot_w = han_u->sot_w[i_w]; - - if ( _(u3h_slot_is_noun(sot_w)) ) { + if ( _(u3h_slot_is_null(sot_w))) { + } else if ( _(u3h_slot_is_noun(sot_w)) ) { u3z(u3h_slot_to_noun(sot_w)); - } - else { + } else { void* hav_v = u3h_slot_to_node(sot_w); if ( 0 == lef_w ) { _ch_free_buck(hav_v); } else { - _ch_free_node(hav_v, lef_w); + _ch_free_node(hav_v, lef_w, pin_o); } } } @@ -721,7 +849,7 @@ u3h_free(u3p(u3h_root) har_p) else if ( _(u3h_slot_is_node(sot_w)) ) { u3h_node* han_u = u3h_slot_to_node(sot_w); - _ch_free_node(han_u, 25); + _ch_free_node(han_u, 25, i_w == 57); } } u3a_wfree(har_u); diff --git a/pkg/noun/hashtable.h b/pkg/noun/hashtable.h index 291ef28a0c..80deb9e2f7 100644 --- a/pkg/noun/hashtable.h +++ b/pkg/noun/hashtable.h @@ -125,6 +125,13 @@ u3_weak u3h_git(u3p(u3h_root) har_p, u3_noun key); + /* u3h_del(); delete from hashtable. + ** + ** `key` is RETAINED + */ + void + u3h_del(u3p(u3h_root) har_p, u3_noun key); + /* u3h_trim_to(): trim to n key-value pairs */ void diff --git a/pkg/noun/hashtable_tests.c b/pkg/noun/hashtable_tests.c index 36afc07b2c..dbd039816b 100644 --- a/pkg/noun/hashtable_tests.c +++ b/pkg/noun/hashtable_tests.c @@ -1,6 +1,7 @@ /// @file #include "noun.h" +#define TEST_SIZE 100000 // defined in noun/hashtable.c c3_w _ch_skip_slot(c3_w mug_w, c3_w lef_w); @@ -14,6 +15,59 @@ _setup(void) u3m_pave(c3y); } +/* _test_put_del(): +*/ +static c3_i +_test_put_del() +{ + u3p(u3h_root) har_p = u3h_new(); + c3_i ret_i = 1; + + c3_w i_w; + for ( i_w = 0; i_w < TEST_SIZE; i_w++ ) { + u3_noun key = u3i_word(i_w); + u3_noun val = u3nc(u3_nul, u3k(key)); + u3h_put(har_p, key, val); + u3z(key); + } + fprintf(stderr, "inserted"); + + for ( i_w = 0; i_w < TEST_SIZE; i_w++ ) { + u3_noun key = u3i_word(i_w); + u3_weak val = u3h_get(har_p, key); + if ( val == u3_none ) { + fprintf(stderr, "failed insert\r\n"); + ret_i = 0; + } + u3z(key); + u3z(val); + } + fprintf(stderr, "presence"); + c3_w del_w[4] = {30, 82, 4921, 535}; + + for ( i_w = 0; i_w < 4; i_w++ ) { + u3_noun key = u3i_word(del_w[i_w]); + u3h_del(har_p, key); + u3z(key); + } + fprintf(stderr, "deleted"); + + for ( i_w = 0; i_w < 4; i_w++ ) { + u3_noun key = u3i_word(del_w[i_w]); + u3_weak val = u3h_get(har_p, key); + if ( u3_none != val ) { + fprintf(stderr, "failed delete\r\n"); + ret_i = 0; + break; + } + } + fprintf(stderr, "presence two"); + u3h_free(har_p); + fprintf(stderr, "freed"); + + return ret_i; +} + /* _test_bit_manipulation(): */ static c3_i @@ -220,6 +274,7 @@ _test_hashtable(void) ret_i &= _test_skip_slot(); ret_i &= _test_cache_trimming(); ret_i &= _test_cache_replace_value(); + ret_i &= _test_put_del(); return ret_i; } diff --git a/pkg/noun/jets/k.h b/pkg/noun/jets/k.h index f4587bef58..27733fb5e0 100644 --- a/pkg/noun/jets/k.h +++ b/pkg/noun/jets/k.h @@ -93,6 +93,11 @@ u3_weak u3kdb_put(u3_noun a, u3_noun b, u3_noun c); + /* u3kdb_del(): map del for key `b` + */ + u3_weak + u3kdb_del(u3_noun a, u3_noun b); + /* u3kdb_has(): test for get. */ u3_noun diff --git a/pkg/noun/jets/q.h b/pkg/noun/jets/q.h index fd7c5981fb..a47838676f 100644 --- a/pkg/noun/jets/q.h +++ b/pkg/noun/jets/q.h @@ -87,6 +87,7 @@ u3_noun u3qdb_any(u3_noun, u3_noun); u3_noun u3qdb_apt(u3_noun); u3_noun u3qdb_bif(u3_noun, u3_noun); + u3_noun u3qdb_del(u3_noun, u3_noun); u3_noun u3qdb_dif(u3_noun, u3_noun); u3_noun u3qdb_gas(u3_noun, u3_noun); u3_noun u3qdb_get(u3_noun, u3_noun); @@ -102,6 +103,7 @@ u3_noun u3qdi_apt(u3_noun); u3_noun u3qdi_bif(u3_noun, u3_noun); + u3_noun u3qdi_del(u3_noun, u3_noun); u3_noun u3qdi_dif(u3_noun, u3_noun); u3_noun u3qdi_gas(u3_noun, u3_noun); u3_noun u3qdi_has(u3_noun, u3_noun); diff --git a/pkg/vere/BUILD.bazel b/pkg/vere/BUILD.bazel index f50642ab89..11cb6e0432 100644 --- a/pkg/vere/BUILD.bazel +++ b/pkg/vere/BUILD.bazel @@ -96,6 +96,9 @@ vere_library( "*.h", "db/*.c", "io/*.c", + "io/*.h", + "io/xmas/*.c", + "io/xmas/*.h", ], exclude = [ "main.c", @@ -195,6 +198,52 @@ cc_test( deps = [":vere"], ) +cc_test( + name = "blake_tests", + timeout = "short", + srcs = ["io/blake.c"], + features = select({ + "@platforms//os:linux": ["fully_static_link"], + "//conditions:default": [], + }), + deps = [":vere"], + defines = ["BLAKE_TEST"] +) + +# see https://github.com/bazelbuild/bazel/issues/680 +cc_library( + name = "xmas_src", + hdrs = ["io/xmas.c"], +) +cc_library( + name = "pact_src", + hdrs = ["io/xmas/pact.c"], +) + +cc_test( + name = "xmas_tests", + timeout = "short", + srcs = ["xmas_tests.c"], + features = select({ + "@platforms//os:linux": ["fully_static_link"], + "//conditions:default": [], + }), + deps = [":vere", ":xmas_src"], + defines = ["XMAS_TEST"] +) + +cc_test( + name = "pact_tests", + timeout = "short", + srcs = ["pact_tests.c"], + features = select({ + "@platforms//os:linux": ["fully_static_link"], + "//conditions:default": [], + }), + deps = [":vere", ":pact_src"], +) + + cc_test( name = "boot_tests", timeout = "short", diff --git a/pkg/vere/auto.c b/pkg/vere/auto.c index 2435458ad4..1aaee81d27 100644 --- a/pkg/vere/auto.c +++ b/pkg/vere/auto.c @@ -439,6 +439,7 @@ u3_auto_init(u3_pier* pir_u) car_u = _auto_link(u3_term_io_init(pir_u), pir_u, car_u); car_u = _auto_link(u3_fore_io_init(pir_u), pir_u, car_u); car_u = _auto_link(u3_lick_io_init(pir_u), pir_u, car_u); + car_u = _auto_link(u3_xmas_io_init(pir_u), pir_u, car_u); return car_u; } diff --git a/pkg/vere/io/ames.c b/pkg/vere/io/ames.c index eecef8ac75..90b24781ad 100644 --- a/pkg/vere/io/ames.c +++ b/pkg/vere/io/ames.c @@ -910,11 +910,11 @@ _ames_send(u3_pact* pac_u) { uv_buf_t buf_u = uv_buf_init((c3_c*)pac_u->hun_y, pac_u->len_w); - c3_i sas_i = uv_udp_send(&pac_u->snd_u, + c3_i sas_i = 0; /*uv_udp_send(&pac_u->snd_u, &sam_u->wax_u, &buf_u, 1, (const struct sockaddr*)&add_u, - _ames_send_cb); + _ames_send_cb); */ if ( sas_i ) { if ( c3y == sam_u->fig_u.net_o ) { @@ -2836,10 +2836,12 @@ _ames_io_start(u3_ames* sam_u) htonl(INADDR_ANY) : htonl(INADDR_LOOPBACK); add_u.sin_port = htons(por_s); + u3l_log("ames: skipping port: %u", por_s); - if ( (ret_i = uv_udp_bind(&sam_u->wax_u, + /*if ( (ret_i = uv_udp_bind(&sam_u->wax_u, (const struct sockaddr*)&add_u, 0)) != 0 ) { + u3l_log("ames: port: %u", por_s); u3l_log("ames: bind: %s", uv_strerror(ret_i)); if ( (c3y == zar_o) && @@ -2851,7 +2853,7 @@ _ames_io_start(u3_ames* sam_u) // XX revise // u3_pier_bail(u3_king_stub()); - } + }*/ uv_udp_getsockname(&sam_u->wax_u, (struct sockaddr *)&add_u, &add_i); u3_assert(add_u.sin_port); @@ -2881,8 +2883,7 @@ _ames_io_start(u3_ames* sam_u) u3z(who); } -/* _ames_ef_turf(): initialize ames I/O on domain(s). -*/ +/* _ames_ef_turf(): initialize ames I/O on domain(s). */ static void _ames_ef_turf(u3_ames* sam_u, u3_noun tuf) { diff --git a/pkg/vere/io/blake.c b/pkg/vere/io/blake.c new file mode 100644 index 0000000000..61b50e03cf --- /dev/null +++ b/pkg/vere/io/blake.c @@ -0,0 +1,822 @@ +/// @file + + +#include "vere.h" +#include +#include +#include "urcrypt.h" +#include "blake.h" + + +#define pf(label, ...) { fprintf(stderr, "%s (%u)\r\n", label, __LINE__); fprintf(stderr, __VA_ARGS__); } +#define pl { fprintf(stderr, "(%u)", __LINE__); } +#define pll(label) { fprintf(stderr, "%s (%u)\n", label, __LINE__); } + +enum blake3_flags { + CHUNK_START = 1 << 0, + CHUNK_END = 1 << 1, + PARENT = 1 << 2, + ROOT = 1 << 3, + KEYED_HASH = 1 << 4, + DERIVE_KEY_CONTEXT = 1 << 5, + DERIVE_KEY_MATERIAL = 1 << 6, +}; + + + + +static void +_log_buf(c3_c* str_c, c3_y* buf_y, c3_w len_w) +{ + c3_w siz_w = 2*len_w + 1; + c3_c* res_c = c3_calloc(siz_w); + c3_w cur_w = 0; + c3_c tmp_c[3]; + for(c3_w idx_w = 0; idx_w < len_w; idx_w++ ) { + snprintf(res_c + (2*idx_w), siz_w - (2*idx_w), "%02x", buf_y[idx_w]); + } + fprintf(stderr, "%s: %s", str_c, res_c); + fprintf(stderr, "\r\n"); + c3_free(res_c); +} + +static void +_log_words(c3_c* str_c, c3_w* buf_w, c3_w len_w) +{ + fprintf(stderr, "%s\r\n", str_c); + for ( c3_w i_w = 0; i_w < len_w; i_w++ ) { + fprintf(stderr, "%u ", buf_w[i_w]); + } + fprintf(stderr, "\r\n"); +} + +void +log_node(blake_node* nod_u) +{ + _log_buf("CV", nod_u->cev_y, BLAKE3_OUT_LEN); + _log_buf("block", nod_u->boq_y, BLAKE3_BLOCK_LEN); + fprintf(stderr, "counter: %" PRIu64 "\r\n", nod_u->con_d); + fprintf(stderr, "length: %u\r\n", nod_u->len_y); + fprintf(stderr, "flag: %x\r\n", nod_u->fag_y); +} + +static void print_proof(void* vod_p, c3_w i_w) { + c3_y* pof_y = (c3_y*)vod_p; + fprintf(stderr, "proof: %u\r\n", i_w); + _log_buf("", pof_y, BLAKE3_OUT_LEN); +} + + + + +// static c3_w IV_WORDS[8] = {0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL, 0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL}; +static c3_y IV[BLAKE3_OUT_LEN] = {103, 230, 9, 106, 133, 174, 103, 187, 114, 243, 110, 60, 58, 245, 79, 165, 127, 82, 14, 81, 140, 104, 5, 155, 171, 217, 131, 31, 25, 205, 224, 91}; +#define ABS_DIFF(x,y) x > y ? x - y : y - x + +#define VEC_SCALING 2 + + +void +vec_init(u3_raw_vec* vec_u, c3_w siz_w) +{ + vec_u->siz_w = siz_w; + vec_u->vod_p = c3_calloc(siz_w * sizeof(void*)); + vec_u->len_w = 0; +} +static void +_vec_each(u3_raw_vec* vec_u, void (*func)(void*, c3_w)) { + for (c3_w i_w = 0; i_w < vec_u->len_w; i_w++) { + func(vec_u->vod_p[i_w], i_w); + } +} + +void +vec_free(u3_raw_vec* vec_u) +{ + c3_free(vec_u->vod_p); +} + +void +vec_flop(u3_raw_vec* vec_u) +{ + for (int i = 0; i < (vec_u->len_w/2); i++) { + c3_w j_w = (vec_u->len_w - 1 -i ); + void* vod_p = vec_u->vod_p[i]; + vec_u->vod_p[i] = vec_u->vod_p[j_w]; + vec_u->vod_p[j_w] = vod_p; + } +} + +void +vec_drop(u3_raw_vec* vec_u) +{ + vec_free(vec_u); + c3_free(vec_u); +} + +u3_raw_vec* +vec_make(c3_w siz_w) +{ + u3_raw_vec* vec_u = c3_calloc(sizeof(u3_raw_vec)); + vec_init(vec_u, siz_w); + return vec_u; +} + + +c3_w +vec_len(u3_raw_vec* vec_u) +{ + return vec_u->len_w; +} + +static void* +_vec_raw_get(u3_raw_vec* vec_u, c3_w idx_w) +{ + if ( vec_u->len_w <= idx_w ) { + return NULL; + } + return vec_u->vod_p[idx_w]; +} + +#define _vec_get(typ,vec,idx) ((typ*)_vec_raw_get(vec, idx)) + +static void* +_vec_raw_got(u3_raw_vec* vec_u, c3_w idx_w) +{ + return vec_u->vod_p[idx_w]; +} + +#define _vec_got(typ,vec,idx) ((typ*)_vec_raw_got(vec, idx)) + + +static void +_vec_resize(u3_raw_vec* vec_u, c3_w siz_w) { + u3_assert( vec_u->len_w <= siz_w ); + void* vod_p = c3_calloc(siz_w * sizeof(void*)); + + memcpy(vod_p, vec_u->vod_p, vec_u->len_w * sizeof(void*)); + c3_free(vec_u->vod_p); + vec_u->vod_p = vod_p; + vec_u->siz_w = siz_w; +} + +void +vec_append(u3_raw_vec* vec_u, void* tem_p) +{ + if(vec_u->siz_w == vec_u->len_w ) { + _vec_resize(vec_u, vec_u->siz_w * VEC_SCALING); + } + vec_u->vod_p[vec_u->len_w] = tem_p; + vec_u->len_w++; +} + +void +vec_copy(u3_raw_vec* dst_u, u3_raw_vec* src_u) { + if ( dst_u->siz_w < src_u->siz_w ) { + _vec_resize(dst_u, src_u->siz_w); + } + for ( c3_w i_w = 0; i_w < src_u->len_w; i_w++ ) { + dst_u->vod_p[i_w] = src_u->vod_p[i_w]; + } + dst_u->len_w = src_u->len_w; +} + +void* +vec_pop(u3_raw_vec* vec_u, c3_w idx_w) +{ + if ( vec_u->len_w == 0 || idx_w >= vec_u->len_w ) { + fprintf(stderr, "Failed pop (len: %u, idx: %u)\r\n", vec_u->len_w, idx_w); + return NULL; + } + void* hit_p = vec_u->vod_p[idx_w]; + vec_u->len_w--; + for ( c3_w i_w = idx_w; i_w < vec_u->len_w; i_w++ ) { + vec_u->vod_p[i_w] = vec_u->vod_p[i_w+1]; + } + return hit_p; +} + +void* +vec_popf(u3_raw_vec* vec_u) +{ + return vec_pop(vec_u, 0); +} + +static void* +_vec_popl(u3_raw_vec* vec_u) +{ + return vec_pop(vec_u, vec_u->len_w - 1); +} + + +static void +_vec_swap(u3_raw_vec* vec_u, c3_w fst_w, c3_w snd_w) { + void* tmp_p = vec_u->vod_p[fst_w]; + vec_u->vod_p[fst_w] = vec_u->vod_p[snd_w]; + vec_u->vod_p[snd_w] = tmp_p; +} + + + +static void _vec_weld_mut(u3_raw_vec* fst_u, u3_raw_vec* snd_u) +{ + if ( fst_u->siz_w <= (fst_u->len_w + snd_u->len_w ) ) { + _vec_resize(fst_u, (fst_u->len_w + snd_u->len_w) * VEC_SCALING ); + } + for ( c3_w i_w = 0; i_w < snd_u->len_w; i_w++ ) { + fst_u->vod_p[i_w + fst_u->len_w] = snd_u->vod_p[i_w]; + } + fst_u->len_w += snd_u->len_w; +} + +//type Hash [32]byte + +//func (h Hash) String() string { return hex.EncodeToString(h[:]) } + +//type Pair [2][8]uint32 + + + +static void +_log_blake_subtree(blake_subtree* sub_u) +{ + fprintf(stderr, "sub: (%llu, %llu)\r\n", sub_u->sin_d, sub_u->dex_d); +} + +void +log_bao(blake_bao* bao_u) +{ + fprintf(stderr, "num: %u\r\n", bao_u->num_w); + fprintf(stderr, "con: %u\r\n", bao_u->con_w); + fprintf(stderr, "sub: (%llu, %llu)\r\n", bao_u->sub_u.sin_d, bao_u->sub_u.dex_d); + fprintf(stderr, "queue\r\n"); + _vec_each(&bao_u->que_u, print_proof); + fprintf(stderr, "stack\r\n"); + _vec_each(&bao_u->sta_u, print_proof); +} + +static c3_y +_count_lead_zeros(c3_d val_d) +{ + if (val_d == 0 ) { + return 64; + } + c3_y ret_y = 0; + if ((val_d & 0xFFFFFFFF00000000ULL) == 0) { ret_y += 32; val_d <<= 32; } + if ((val_d & 0xFFFF000000000000ULL) == 0) { ret_y += 16; val_d <<= 16; } + if ((val_d & 0xFF00000000000000ULL) == 0) { ret_y += 8; val_d <<= 8; } + if ((val_d & 0xF000000000000000ULL) == 0) { ret_y += 4; val_d <<= 4; } + if ((val_d & 0xC000000000000000ULL) == 0) { ret_y += 2; val_d <<= 2; } + if ((val_d & 0x8000000000000000ULL) == 0) { ret_y += 1; val_d <<= 1; } + return ret_y; +} + +static c3_y _count_trail_zero(c3_d val_d) +{ + if (val_d == 0 ) { + return 64; + } + c3_y ret_y = 0; + if ((val_d & 0x00000000FFFFFFFFULL) == 0) { ret_y += 32; val_d >>= 32; } + if ((val_d & 0x000000000000FFFFULL) == 0) { ret_y += 16; val_d >>= 16; } + if ((val_d & 0x00000000000000FFULL) == 0) { ret_y += 8; val_d >>= 8; } + if ((val_d & 0x000000000000000FULL) == 0) { ret_y += 4; val_d >>= 4; } + if ((val_d & 0x0000000000000003ULL) == 0) { ret_y += 2; val_d >>= 2; } + if ((val_d & 0x0000000000000001ULL) == 0) { ret_y += 1; val_d >>= 1; } + return ret_y; +} + +static c3_y _bitlen(c3_d bit_d) +{ + return 64 - _count_lead_zeros(bit_d); +} + +static c3_d +_height(blake_subtree* sub_u) +{ + c3_d ret_d = _bitlen(ABS_DIFF(sub_u->dex_d, sub_u->sin_d)) - 1; + return ret_d; +} + +static c3_d +_largest_pow2(c3_d val_d) +{ + c3_d ret_d = 1 << (_bitlen(val_d-1) - 1); + return ret_d; +} + +static void +y_to_w(c3_y* byt_y, c3_w wod_w[16]) +{ + for ( c3_w i_w = 0; i_w < 16; i_w++ ) { + c3_w cur_w = 0; + for ( c3_w j_w = 0; j_w < 4; j_w++ ) { + cur_w |= byt_y[(i_w * 4) + j_w] << (8*j_w); + } + wod_w[i_w] = cur_w; + } +} + +static void +w_to_y(c3_w wod_w[16], c3_y byt_y[64]) +{ + for ( c3_w i_w = 0; i_w < 16; i_w++ ) { + for ( c3_w j_w = 0; j_w < 4; j_w++ ) { + byt_y[(i_w * 4) + j_w] = (wod_w[i_w] >> (8*j_w)) & 0xff; + } + } +} + + +static void +_compress_node(c3_y out_y[BLAKE3_BLOCK_LEN], blake_node* nod_u) +{ + urcrypt_blake3_compress(nod_u->cev_y, + nod_u->boq_y, + nod_u->len_y, + nod_u->con_d, + nod_u->fag_y, + out_y); +} + + +void +make_chain_value(c3_y out_y[32], blake_node* nod_u) +{ + c3_y tmp_y[64]; + _compress_node(tmp_y, nod_u); + memcpy(out_y, tmp_y, BLAKE3_OUT_LEN); +} + +static blake_node* +_compress_chunk(c3_y* dat_y, c3_w dat_w, c3_y cev_y[BLAKE3_OUT_LEN], c3_d con_d, c3_w fag_y) +{ + blake_node* nod_u = c3_calloc(sizeof(blake_node)); + nod_u->con_d = con_d; + nod_u->fag_y = fag_y; + memcpy(nod_u->cev_y, cev_y, BLAKE3_OUT_LEN); + urcrypt_blake3_chunk_output(dat_w, dat_y, nod_u->cev_y, nod_u->boq_y, &nod_u->len_y, &nod_u->con_d, &nod_u->fag_y); + return nod_u; +} + +blake_node* blake_leaf_hash(c3_y* dat_y, c3_w dat_w, c3_d con_d) +{ + return _compress_chunk(dat_y, dat_w, IV, con_d, 0); +} + +static blake_node* +_parent_node(c3_y sin_y[BLAKE3_OUT_LEN], c3_y dex_y[BLAKE3_OUT_LEN], c3_y key_y[BLAKE3_OUT_LEN], c3_w fag_y) +{ + blake_node* nod_u = c3_calloc(sizeof(blake_node)); + nod_u->con_d = 0; + memcpy(nod_u->cev_y, key_y, BLAKE3_OUT_LEN); + nod_u->len_y = BLAKE3_BLOCK_LEN; + nod_u->fag_y = fag_y | PARENT; + memcpy(nod_u->boq_y, sin_y, BLAKE3_OUT_LEN); + memcpy(nod_u->boq_y + BLAKE3_OUT_LEN, dex_y, BLAKE3_OUT_LEN); + return nod_u; +} + +static blake_node* +_parent_hash(blake_node* sin_u, blake_node* dex_u) +{ + c3_y sin_y[BLAKE3_OUT_LEN]; + c3_y dex_y[BLAKE3_OUT_LEN]; + make_chain_value(sin_y, sin_u); + make_chain_value(dex_y, dex_u); + return _parent_node(sin_y, dex_y, IV, 0); +} + + + +static void +_root_hash(c3_y out_y[64], blake_node* nod_u) +{ + nod_u->fag_y |= ROOT; + _compress_node(out_y, nod_u); +} + +void print_pair(void* vod_p, c3_w i_w) { + blake_pair* par_u = (blake_pair*)vod_p; + fprintf(stderr, "pair: %u", i_w); + _log_buf("sin: ", par_u->sin_y, BLAKE3_OUT_LEN); + _log_buf("dex: ", par_u->dex_y, BLAKE3_OUT_LEN); +} + +c3_w emp_w = 1024; +static c3_y emp_y[1024] = {0}; + +static void recurse_blake_subtree(blake_subtree* sub_u, blake_node* nod_u, u3_vec(pair)* par_u) +{ + c3_d hit_d = _height(sub_u); + if ( hit_d == 0 ) { + blake_node* new_u = blake_leaf_hash(emp_y, emp_w, sub_u->sin_d); + memcpy(nod_u, new_u, sizeof(blake_node)); + return; + } + + c3_d mid_d = sub_u->sin_d + _largest_pow2(ABS_DIFF(sub_u->dex_d, sub_u->sin_d)); + + blake_subtree* sin_u = c3_calloc(sizeof(blake_subtree)); + *sin_u = (blake_subtree){sub_u->sin_d, mid_d}; + blake_node* lod_u = c3_calloc(sizeof(blake_node)); + u3_vec(pair)* lar_u = vec_make(8); + recurse_blake_subtree(sin_u, lod_u, lar_u); + + blake_subtree* dex_u = c3_calloc(sizeof(blake_subtree)); + *dex_u = (blake_subtree){mid_d, sub_u->dex_d}; + blake_node* rod_u = c3_calloc(sizeof(blake_node)); + u3_vec(pair)* rar_u = vec_make(8); + recurse_blake_subtree(dex_u, rod_u, rar_u); + + blake_pair* new_u = c3_calloc(sizeof(blake_pair)); + make_chain_value(new_u->sin_y, lod_u); + make_chain_value(new_u->dex_y, rod_u); + memcpy(nod_u, _parent_hash(lod_u, rod_u), sizeof(blake_node)); + + vec_append(par_u, new_u); + _vec_weld_mut(par_u, lar_u); + _vec_weld_mut(par_u, rar_u); +} + +static void +_bao_build(c3_d num_d, c3_y has_y[64], u3_vec(c3_w[8])* pof_u, u3_vec(pair)* par_u) +{ + blake_subtree* sub_u = c3_calloc(sizeof(blake_subtree)); + *sub_u = (blake_subtree){0, num_d}; + blake_node* nod_u = c3_calloc(sizeof(blake_node)); + recurse_blake_subtree(sub_u, nod_u, par_u); + _root_hash(has_y, nod_u); + + if ( vec_len(par_u) != 0 ) { + for ( c3_w i_w = _bitlen(num_d - 1); i_w > 1; i_w-- ) { + blake_pair* pir_u = vec_popf(par_u); + vec_append(pof_u, pir_u->dex_y); + } + blake_pair* pir_u = vec_popf(par_u); + vec_append(pof_u, pir_u->dex_y); + vec_append(pof_u, pir_u->sin_y); + for ( c3_w i_w = 0; i_w < (vec_len(pof_u) >> 1); i_w++ ) { + c3_w jay_w = vec_len(pof_u) - i_w - 1; + _vec_swap(pof_u, i_w, jay_w); + } + } +} + +static void +_push_leaf(blake_bao* bao_u, c3_y lef_y[BLAKE3_OUT_LEN]) +{ + vec_append(&bao_u->que_u, lef_y); +} + +static void +_pop_leaf(c3_y out_y[BLAKE3_OUT_LEN], blake_bao* bao_u) +{ + c3_y* res_y = vec_popf(&bao_u->que_u); + memcpy(out_y, res_y, BLAKE3_OUT_LEN); + c3_free(res_y); +} + +static void +_push_parent(blake_bao* bao_u, c3_y par_y[BLAKE3_OUT_LEN]) +{ + vec_append(&bao_u->sta_u, par_y); +} + +static void +_pop_parent(c3_y out_y[BLAKE3_OUT_LEN], blake_bao* bao_u) +{ + c3_y* res_y = _vec_popl(&bao_u->sta_u); + memcpy(out_y, res_y, BLAKE3_OUT_LEN); + c3_free(res_y); +} + +static void +_verifier_next(blake_bao* bao_u) +{ + if ( _height(&bao_u->sub_u) == 0 ) { + bao_u->sub_u.sin_d += 1; + bao_u->sub_u.dex_d += (1 << _count_trail_zero(bao_u->sub_u.dex_d)); + if ( bao_u->sub_u.dex_d > bao_u->num_w ) { + bao_u->sub_u.dex_d = bao_u->num_w; + } + } else { + bao_u->sub_u = (blake_subtree){bao_u->sub_u.sin_d, bao_u->sub_u.sin_d + _largest_pow2(ABS_DIFF(bao_u->sub_u.dex_d, bao_u->sub_u.sin_d))}; + } +} + +static void +_push_leaves(blake_bao* bao_u, c3_y lef_y[BLAKE3_OUT_LEN], c3_y rig_y[BLAKE3_OUT_LEN]) +{ + _push_leaf(bao_u, lef_y); + _push_leaf(bao_u, rig_y); + _verifier_next(bao_u); + _verifier_next(bao_u); +} + +static c3_o +_veri_check_leaf(blake_bao* bao_u, c3_y* dat_y, c3_w dat_w) +{ + if ( vec_len(&bao_u->que_u) > 0 ) { + c3_y out_y[BLAKE3_OUT_LEN]; + _pop_leaf(out_y, bao_u); + c3_y cav_y[BLAKE3_OUT_LEN]; + blake_node* nod_u = blake_leaf_hash(dat_y, dat_w, bao_u->con_w); + make_chain_value(cav_y, nod_u); + bao_u->con_w++; + c3_free(nod_u); + return 0 == memcmp(cav_y, out_y, BLAKE3_OUT_LEN) ? c3y : c3n; + } else if ( vec_len(&bao_u->sta_u) > 0 ) { + c3_y out_y[BLAKE3_OUT_LEN]; + _pop_parent(out_y, bao_u); + c3_y cav_y[BLAKE3_OUT_LEN]; + blake_node* nod_u = blake_leaf_hash(dat_y, dat_w, bao_u->con_w); + make_chain_value(cav_y, nod_u); + c3_free(nod_u); + bao_u->con_w++; + return 0 == memcmp(cav_y, out_y, BLAKE3_OUT_LEN) ? c3y : c3n; + } + return c3n; +} + +static c3_o +_veri_check_pair(blake_bao* bao_u, blake_pair* par_u) +{ + if ( vec_len(&bao_u->sta_u) == 0 ) { + fprintf(stderr, "bailing empty stack\r\n"); + return c3n; + } + c3_y par_y[BLAKE3_OUT_LEN]; + // par_y is wrong + _pop_parent(par_y, bao_u); + blake_node* nod_u = _parent_node(par_u->sin_y, par_u->dex_y, IV, 0); + c3_y cav_y[BLAKE3_OUT_LEN]; + make_chain_value(cav_y, nod_u); + c3_free(nod_u); + return _(memcmp(par_y, cav_y, BLAKE3_OUT_LEN) == 0); +} + +static c3_o +_at_leaf(blake_subtree* sub_u) +{ + return (sub_u->sin_d+1 == sub_u->dex_d) ? c3y : c3n; +} + + +blake_bao* +blake_bao_make(c3_w num_w, u3_vec(c3_y[BLAKE3_OUT_LEN])* pof_u) +{ + blake_bao* bao_u = c3_calloc(sizeof(blake_bao)); + bao_u->num_w = num_w; + bao_u->con_w = 0; + bao_u->sub_u = (blake_subtree){0,1}; + if ( vec_len(pof_u) == 0 ) { + if ( num_w < 2 ) { + c3_free(bao_u); + return NULL; + } + vec_init(&bao_u->sta_u, 1); + vec_init(&bao_u->que_u, 1); + return bao_u; + } + c3_y* fst_y = vec_popf(pof_u); + c3_y* snd_y = vec_popf(pof_u); + vec_init(&bao_u->sta_u, 8); + vec_init(&bao_u->que_u, 8); + vec_copy(&bao_u->sta_u, pof_u); + vec_flop(&bao_u->sta_u); + _push_leaves(bao_u, fst_y, snd_y); + return bao_u; +} + +static void +_free(void* vod_p, c3_w i_w) +{ + c3_free(vod_p); +} + +void +blake_bao_free(blake_bao* bao_u) +{ + _vec_each(&bao_u->sta_u, _free); + _vec_each(&bao_u->que_u, _free); + c3_free(bao_u); +} + +static void +_push_parents(blake_bao* bao_u, blake_pair* par_u) +{ + c3_y* fst_y = c3_calloc(BLAKE3_OUT_LEN); + c3_y* snd_y = c3_calloc(BLAKE3_OUT_LEN); + memcpy(fst_y, par_u->dex_y, BLAKE3_OUT_LEN); + memcpy(snd_y, par_u->sin_y, BLAKE3_OUT_LEN); + _push_parent(bao_u, fst_y); + _push_parent(bao_u, snd_y); +} + +c3_y +blake_bao_verify(blake_bao* bao_u, c3_y* dat_y, c3_w dat_w, blake_pair* par_u) +{ + if ( c3n == _veri_check_leaf(bao_u, dat_y, dat_w) ) { + return BAO_FAILED; + } + if ( par_u == NULL ) { + return BAO_GOOD; + } + if ( c3n == _veri_check_pair(bao_u, par_u) ) { + return BAO_FAILED; + } + _verifier_next(bao_u); + if ( _at_leaf(&bao_u->sub_u) == c3y ) { + c3_y* fst_y = c3_calloc(BLAKE3_OUT_LEN); + memcpy(fst_y, par_u->sin_y, BLAKE3_OUT_LEN); + c3_y* snd_y = c3_calloc(BLAKE3_OUT_LEN); + memcpy(snd_y, par_u->dex_y, BLAKE3_OUT_LEN); + _push_leaves(bao_u, fst_y, snd_y); + } else { + _push_parents(bao_u, par_u); + } + if ( bao_u->con_w == bao_u->num_w ) { + return BAO_DONE; + } + return BAO_GOOD; +} + +#ifdef BLAKE_TEST + + +static void _test_lead_zeros() +{ + #define asrt(x,y) if ( x != y ) { fprintf(stderr, "failed (line: %u) got %u expected %u", __LINE__, x,y); exit(1); } + // Test with 0, should be 64 leading zeros + asrt(_count_lead_zeros(0ULL), 64); + + // Test with maximum unsigned 64-bit integer, should be 0 leading zeros + asrt(_count_lead_zeros(0xFFFFFFFFFFFFFFFFULL), 0); + + // Test with 1 (which is 2^0), should be 63 leading zeros + asrt(_count_lead_zeros(1ULL), 63); + + // Test with 2^63, should be 1 leading zero + asrt(_count_lead_zeros(0x4000000000000000ULL), 1); + + // Test with a number in the middle, for example 2^31, should be 32 leading zeros + asrt(_count_lead_zeros(0x0000000080000000ULL), 32); + + // Test with a small number, should still recognize leading zeros correctly + asrt(_count_lead_zeros(0x00000000000000FFULL), 56); + + // Additional tests for edge cases + asrt(_count_lead_zeros(0x2000000000000000ULL), 2); + + // Test with a value just below the halfway mark, should have 33 leading zeros + asrt(_count_lead_zeros(0x000000007FFFFFFFULL), 33); + + asrt(_bitlen(7), 3); + + asrt(_count_trail_zero(3), 0); + #undef asrt +} + + +#if 0 +static void _test_bao() +{ + c3_w dat_w = 1024; + c3_y* dat_y = c3_calloc(dat_w); + for ( c3_w num_w = 1; num_w <= 100; num_w++ ) { + c3_y has_y[BLAKE3_BLOCK_LEN]; + u3_vec(c3_y[8])* pof_u = vec_make(10); + u3_vec(blake_pair)* par_u = vec_make(10); + _bao_build(num_w, has_y, pof_u, par_u); + + blake_bao bao_u; + memset(&bao_u, 0, sizeof(blake_bao)); + _veri_init(&bao_u, num_w); + if ( c3n == _verifier_init(&bao_u, has_y, pof_u) ) { + fprintf(stderr, "Failed on %u\r\n", num_w); + exit(1); + } + + if ( num_w == 1 ) { + c3_y out_y[BLAKE3_BLOCK_LEN]; + blake_node* nod_u = blake_leaf_hash(dat_y, dat_w, 0); + _root_hash(out_y, nod_u); + if ( memcmp(out_y, has_y, BLAKE3_BLOCK_LEN) != 0 ) { + _log_buf("expected", has_y, BLAKE3_BLOCK_LEN); + _log_buf("got", out_y, BLAKE3_BLOCK_LEN); + + fprintf(stderr, "1 special case\r\n"); + } + continue; + } + for ( c3_w i_w = 0; i_w < num_w; i_w++ ) { + if ( c3n == _veri_check_leaf(&bao_u, dat_y, dat_w) ) { + fprintf(stderr, "Check leaf %u failed for %u\r\n", i_w, num_w); + exit(1); + } + + // pl + // _log_verifier(&bao_u); + if ( i_w < vec_len(par_u) ) { + blake_pair* pir_u = _vec_get(blake_pair, par_u, i_w); + if ( _veri_check_pair(&bao_u, pir_u) == c3n ) { + fprintf(stderr, "check pair failed (%u, %u)", i_w, num_w); + exit(1); + } + _verifier_next(&bao_u); + if ( _height(&bao_u.sub_u) == 0 ) { + _push_leaf(&bao_u, pir_u->sin_y); + _push_leaf(&bao_u, pir_u->dex_y); + _verifier_next(&bao_u); + _verifier_next(&bao_u); + } else { + _push_parent(&bao_u, pir_u->dex_y); + _push_parent(&bao_u, pir_u->sin_y); + } + } + } + } +} +#endif + +static void print_int(void* vod_p, c3_w i_w) { + c3_w* int_w = (c3_w*)vod_p; + fprintf(stderr, "int: %u\r\n", *int_w); +} + +static void _test_vec() { + fprintf(stderr, "Making vec"); + u3_vec(c3_w)* vec_u = vec_make(2); + + c3_w fst = 1; + c3_w snd = 2; + c3_w thd = 3; + vec_append(vec_u, &fst); + fprintf(stderr, "put one\r\n"); + vec_append(vec_u, &snd); + fprintf(stderr, "put two\r\n"); + vec_append(vec_u, &thd); + fprintf(stderr, "put three\r\n"); + + c3_w* one_w = vec_popf(vec_u); + + if ( *one_w != 1 ) { + fprintf(stderr, "(one) Vec failure\r\n"); + exit(1); + } + fprintf(stderr, "popped %u\r\n", *one_w); + + c3_w* two_w = vec_popf(vec_u); + fprintf(stderr, "two pointer %p, %p\r\n", &snd, two_w); + if ( *two_w != 2 ) { + fprintf(stderr, "(two) Vec failure\r\n"); + exit(1); + } + fprintf(stderr, "popped %u\r\n", *two_w); + + c3_w* thr_w = vec_popf(vec_u); + if ( *thr_w != 3 ) { + fprintf(stderr, "(three) Vec failure\r\n"); + exit(1); + } + + fprintf(stderr, "popped %u\r\n", *thr_w); + + if ( 0 != vec_len(vec_u) ) { + fprintf(stderr, "Vec should be empty\r\n"); + exit(1); + } + + vec_append(vec_u, &fst); + vec_append(vec_u, &snd); + vec_append(vec_u, &thd); + c3_w for_w = 4; + c3_w fiv_w = 5; + c3_w six_w = 6; + u3_vec(c3_w)* new_u = vec_make(4); + vec_append(new_u, &for_w); + vec_append(new_u, &fiv_w); + vec_append(new_u, &six_w); + + _vec_weld_mut(vec_u, new_u); + _vec_each(vec_u, print_int); + + + + + + vec_free(vec_u); + c3_free(vec_u); +} + +int main() { + _test_vec(); + // _test_root_hash(); + _test_lead_zeros(); + // _test_bao(); + + return 0; +} + +#endif diff --git a/pkg/vere/io/blake.h b/pkg/vere/io/blake.h new file mode 100644 index 0000000000..3fd3d0a3d5 --- /dev/null +++ b/pkg/vere/io/blake.h @@ -0,0 +1,80 @@ +#ifndef VERE_BLAKE_H +#define VERE_BLAKE_H + +#include "vere.h" +#include "ivory.h" + +#include "noun.h" +#include "ur.h" + +#define BLAKE3_BLOCK_LEN 64 +#define BLAKE3_OUT_LEN 32 + +#define u3_vec(type) u3_raw_vec + +typedef enum _bao_ingest_result { + BAO_BAD_ORDER = 1, + BAO_FAILED = 2, + BAO_GOOD = 3, + BAO_DONE = 4, +} bao_ingest_result; + +typedef struct _blake_pair { + c3_y sin_y[BLAKE3_OUT_LEN]; + c3_y dex_y[BLAKE3_OUT_LEN]; +} blake_pair; + +typedef struct _u3_raw_vec { + c3_w siz_w; + c3_w len_w; + void** vod_p; +} u3_raw_vec; + +typedef struct _blake_node { + c3_y cev_y[BLAKE3_OUT_LEN]; + c3_y boq_y[BLAKE3_BLOCK_LEN]; + c3_d con_d; + c3_y len_y; + c3_y fag_y; +} blake_node; + +typedef struct _blake_subtree { + c3_d sin_d; + c3_d dex_d; +} blake_subtree; + +typedef struct _blake_bao { + c3_w num_w; // number of leaves == num of packets + c3_w con_w; // next packet to be ingested + blake_subtree sub_u; // internal cursor + u3_vec(c3_y[BLAKE3_OUT_LEN]) que_u; // internal + u3_vec(c3_w[BLAKE3_OUT_LEN]) sta_u; // interal +} blake_bao; + +void* vec_popf(u3_raw_vec*); +void* vec_pop(u3_raw_vec*, c3_w); + +void vec_init(u3_raw_vec*, c3_w); + +c3_w vec_len(u3_raw_vec*); + +void vec_append(u3_raw_vec*, void*); + +u3_raw_vec* vec_make(c3_w); + +void vec_free(u3_raw_vec*); +void vec_drop(u3_raw_vec*); + +blake_node* blake_leaf_hash(c3_y* dat_y, c3_w dat_w, c3_d con_d); + +blake_bao* blake_bao_make(c3_w, u3_raw_vec* pof_u); +void blake_bao_free(blake_bao*); + +void make_chain_value(c3_y*, blake_node*); + +void log_node(blake_node*); +void log_bao(blake_bao*); + +c3_y blake_bao_verify(blake_bao*, c3_y*, c3_w, blake_pair* par_u); + +#endif \ No newline at end of file diff --git a/pkg/vere/io/cong.h b/pkg/vere/io/cong.h new file mode 100644 index 0000000000..0db5276c1e --- /dev/null +++ b/pkg/vere/io/cong.h @@ -0,0 +1,34 @@ +/// @file +/// +#include "vere.h" +#include +#include + +#include "noun.h" +#include "ur.h" + +typedef struct _u3_gage { + c3_w rtt_w; // rtt + c3_w rto_w; // rto + c3_w rtv_w; // rttvar + c3_w wnd_w; // cwnd + c3_w wnf_w; // cwnd fraction + c3_w sst_w; // ssthresh + c3_w con_w; // counter + void* alg_u; // algorithm backpointer + c3_c* alg_c; // algorithm name + // + uv_timer_t tim_u; +} u3_gage; + +typedef void (*u3_gage_func)(u3_gage*); + + +typedef struct _u3_gage_alg { + u3_gage_func int_f; //initialise + u3_gage_func don_f; // dispose + u3_gage_func ack_f; // received ack + u3_gage_func los_f; // lost +} u3_gage_alg; + + diff --git a/pkg/vere/io/cubic.c b/pkg/vere/io/cubic.c new file mode 100644 index 0000000000..1f9eb33cfd --- /dev/null +++ b/pkg/vere/io/cubic.c @@ -0,0 +1,129 @@ +/// @file +/// +#include "vere.h" +#include +#include + +#include "noun.h" +#include "ur.h" +#include "cubic.h" + +#define FAST_CONVERGENCE 0 + +const c3_d cee_d = 13; // (0.4*32) +const c3_d bet_d = 3; // (.2*16) + + +static c3_d +_get_now_micros() +{ + struct timeval tim_u; + gettimeofday(&tim_u, NULL); + return (tim_u.tv_sec * 1000000) + tim_u.tv_usec; +} + +static c3_d +_cube(c3_d val_d) +{ + return val_d * val_d * val_d; + +} + +void u3_cbic_init(u3_gage* gag_u) +{ + gag_u->alg_u = c3_calloc(sizeof(u3_cbic)); + gag_u->alg_c = "CUBIC"; +} + +void u3_cbic_done(u3_gage* gag_u) +{ + free(gag_u->alg_u); +} + + +void u3_cbic_reset(u3_gage* gag_u) +{ + u3_cbic* cub_u = gag_u->alg_u; + cub_u->las_w = 0; + cub_u->poc_d = 0; + cub_u->rig_w = 0; + cub_u->del_w = 0; + cub_u->win_w = 0; + cub_u->cac_w = 0; +} + + +void u3_cbic_tcp(u3_gage* gag_u) +{ + u3_cbic* cub_u = gag_u->alg_u; + + /*sat_u.tcp_w = sat_u.tcp_w + ((c3_w)((3*bet_f)/(2-bet_f)) * (sat_u.cac_w/con_u.wnd_w)); + sat_u.cac_w = 0; + if ( sat_u.tcp_w > con_u.wnd_w ) { + sat_u.max_w = con_u.wnd_w/(sat_u.tcp_w-con_u.wnd_w); + if ( sat_u.cnt_w > sat_u.max_w ) { + sat_u.cnt_w = sat_u.max_w; + } + } */ +} + +void u3_cbic_update(u3_gage* gag_u) +{ + u3_cbic* cub_u = gag_u->alg_u; + cub_u->cac_w += 1; + c3_d tim_d = _get_now_micros(); + + // if no epoch start set, then begin now + if ( 0 == cub_u->poc_d ) { + cub_u->poc_d = tim_d; + if ( ( gag_u->wnd_w < cub_u->las_w ) && FAST_CONVERGENCE ) { + //sat_u.las_w = con_u.wnd_w * + // set origin point to w last max + } else { + cub_u->kay_w = 0; + cub_u->rig_w = gag_u->wnd_w; + } + cub_u->cac_w = 1; + cub_u->win_w = gag_u->wnd_w; + } + c3_d tee_d = tim_d + cub_u->del_w - cub_u->poc_d; + c3_d tar_d = cub_u->rig_w + ((cee_d * _cube(tee_d - cub_u->kay_w)) >> 5); + if ( tar_d > gag_u->wnd_w ) { + cub_u->cnt_w = gag_u->wnd_w / ( tar_d - gag_u->wnd_w ); + } else { + cub_u->cnt_w = gag_u->wnd_w * 100; + } + if ( c3y == cub_u->tcp_o ) { + u3_cbic_tcp(gag_u); + } +} + + +void u3_cbic_on_ack(u3_gage* gag_u) +{ + c3_w rtt_w = gag_u->rtt_w; // TODO actually update + u3_cbic* cub_u = gag_u->alg_u; + if ( 0 == cub_u->del_w ) { + cub_u->del_w = c3_min(cub_u->del_w, rtt_w); + } else { + cub_u->del_w = rtt_w; + } + + if ( gag_u->wnd_w <= gag_u->sst_w ) { + gag_u->wnd_w += 1; + } else { + if ( gag_u->wnf_w > gag_u->wnd_w ) { + gag_u->wnd_w += 1; + gag_u->wnf_w = 0; + } else { + gag_u->wnf_w += 1; + } + } +} + +void u3_cbic_lost(u3_gage* gag_u) +{ + +} + + diff --git a/pkg/vere/io/cubic.h b/pkg/vere/io/cubic.h new file mode 100644 index 0000000000..1b06938ea1 --- /dev/null +++ b/pkg/vere/io/cubic.h @@ -0,0 +1,33 @@ +/// @file +/// +#include "vere.h" +#include +#include + +#include "noun.h" +#include "ur.h" +#include "cong.h" + + +typedef struct _u3_cbic { + c3_w las_w; // w_last_max + c3_d poc_d; // epoch start + c3_w rig_w; // origin point + c3_w del_w; // delay min + c3_w win_w; // w_tcp + c3_w cac_w; // ack count + c3_w kay_w; // K + c3_w cnt_w; // cnt + c3_o tcp_o; // tcp friendliness + c3_w tcp_w; // w_tcp + c3_w max_w; // max count +} u3_cbic; + + +void u3_cbic_init(u3_gage*); + +void u3_cbic_done(u3_gage*); + +void u3_cbic_on_ack(u3_gage*); + +void u3_cbic_lost(u3_gage*); diff --git a/pkg/vere/io/reno.c b/pkg/vere/io/reno.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/pkg/vere/io/serial.h b/pkg/vere/io/serial.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/pkg/vere/io/xmas.c b/pkg/vere/io/xmas.c new file mode 100644 index 0000000000..7dd8c141a8 --- /dev/null +++ b/pkg/vere/io/xmas.c @@ -0,0 +1,2447 @@ +/// @file + +#include "vere.h" +#include "ivory.h" + + +#include "noun.h" +#include "ur.h" +#include "cubic.h" +#include "xmas/xmas.h" +#include "xmas/bitset.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "blake.h" + +c3_o dop_o = c3n; + +// #define XMAS_DEBUG c3y +//#define XMAS_TEST +#define RED_TEXT "\033[0;31m" +#define DEF_TEXT "\033[0m" +#define REORDER_THRESH 5 + +// logging and debug symbols +#define XMAS_SYM_DESC(SYM) XMAS_DESC_ ## SYM +#define XMAS_SYM_FIELD(SYM) XMAS_FIELD_ ## SYM +#ifdef XMAS_DEBUG + #define XMAS_LOG(SYM, ...) { sam_u->sat_u.XMAS_SYM_FIELD(SYM)++; u3l_log("xmas: (%u) %s", __LINE__, XMAS_SYM_DESC(SYM)); } +#else + #define XMAS_LOG(SYM, ...) { sam_u->sat_u.XMAS_SYM_FIELD(SYM)++; } +#endif + +typedef struct _u3_xmas_stat { + c3_w dop_w; // dropped for other reasons + c3_w ser_w; // dropped for serialisation + c3_w aut_w; // droppped for auth + c3_w apa_w; // dropped bc no interest + c3_w inv_w; // non-fatal invariant violation + c3_w dup_w; // duplicates +} u3_xmas_stat; + +#define XMAS_DESC_STRANGE "dropped strange packet" +#define XMAS_FIELD_STRANGE dop_w + +#define XMAS_DESC_SERIAL "dropped packet (serialisation)" +#define XMAS_FIELD_SERIAL ser_w + +#define XMAS_DESC_AUTH "dropped packet (authentication)" +#define XMAS_FIELD_AUTH aut_w + +#define XMAS_DESC_INVARIANT "invariant violation" +#define XMAS_FIELD_INVARIANT inv_w + +#define XMAS_DESC_APATHY "dropped packet (no interest)" +#define XMAS_FIELD_APATHY apa_w + +#define XMAS_DESC_DUPE "dropped packet (duplicate)" +#define XMAS_FIELD_DUPE dup_w + +// routing table sentinels +#define XMAS_CZAR 1 // pending dns lookup +#define XMAS_ROUT 2 // have route + +/** typedef u3_xmas_pack_stat u3_noun + * [last=@da tries=@ud] + */ +typedef struct _u3_pact_stat { + c3_d sen_d; // last sent + c3_y sip_y; // skips + c3_y tie_y; // tries + c3_y dup_y; // dupes +} u3_pact_stat; + +typedef struct _u3_peer_last { + c3_d acc_d; // time of last access + c3_d son_d; // time of sponsor check +} u3_peer_last; + +typedef struct _u3_misord_buf { + c3_y* fra_y; + c3_w len_w; + c3_w num_w; + blake_pair* par_u; +} u3_misord_buf; + +typedef struct _u3_xmas_pict { + uv_udp_send_t snd_u; + struct _u3_xmas* sam_u; + u3_xmas_pact pac_u; +} u3_xmas_pict; + +typedef struct _u3_pend_req { + c3_w nex_w; // number of the next fragment to be sent + c3_w tot_w; // total number of fragments expected + uv_timer_t tim_u; // timehandler + c3_y* dat_y; // ((mop @ud *) lte) + c3_w len_w; + c3_w lef_w; // lowest fragment number currently in flight/pending + c3_w old_w; // frag num of oldest packet sent + c3_w ack_w; // highest acked fragment number + u3_lane lan_u; // last lane heard + u3_xmas_auth aum_u; + u3_gage* gag_u; // congestion control + u3_vec(u3_misord_buf) mis_u; // misordered blake hash + blake_bao* bao_u; // blake verifier + u3_xmas_pict* pic_u; // preallocated request packet + u3_pact_stat* wat_u; // ((mop @ud packet-state) lte) + u3_bitset was_u; // ((mop @ud packet-state) lte) + c3_y pad_y[64]; +} u3_pend_req; + +typedef struct _u3_czar_info { + c3_w pip_w; // IP of galaxy + c3_y imp_y; // galaxy number + struct _u3_xmas* sam_u; // backpointer + time_t tim_t; // time of retrieval + c3_c* dns_c; // domain + u3_noun pen; // (list @) of pending packet +} u3_czar_info; + +/* _u3_xmas: next generation networking + */ +typedef struct _u3_xmas { + u3_auto car_u; + u3_pier* pir_u; + union { + uv_udp_t wax_u; + uv_handle_t had_u; + }; + u3_xmas_stat sat_u; // statistics + c3_l sev_l; // XX: ?? + c3_o for_o; // is forwarding + u3p(u3h_root) her_p; // (map ship u3_peer) + u3p(u3h_root) lan_p; // (map [lane ship] u3_gage) + u3p(u3h_root) req_p; // (map [ship rift path] u3_pend_req) + u3p(u3h_root) cac_p; // (map name packet=@) // response cache + u3p(u3h_root) pit_p; // (map name [first=@ last=@ our=? for=(set lane)]) + u3p(u3h_root) our_p; // (map name [packet=@ time=@]) // request set + u3_czar_info imp_u[256]; // galaxy information + c3_c* dns_c; // turf (urbit.org) + c3_d tim_d; // XX: move to u3_pend_req +} u3_xmas; + + +typedef struct _u3_peer { + u3_peer_last las_u; // last check timestamps + u3_lane dir_u; // direct lane (if any) + u3_lane ind_u; // indirect lane (if any) + c3_s imp_s; // galaxy + u3_xmas* sam_u; // backpointer +} u3_peer; + +// Sent request +// because of lifecycles a u3_xmas_pact may have several libuv +// callbacks associated with it, so we can't those as callback +// instead just alloc new buffer and stick here +typedef struct _u3_seal { + uv_udp_send_t snd_u; // udp send request + u3_xmas* sam_u; + c3_w len_w; + c3_y* buf_y; +} u3_seal; + +static c3_d +get_millis() { + struct timeval tp; + + gettimeofday(&tp, NULL); + return (tp.tv_sec * 1000) + (tp.tv_usec / 1000); + // Convert the seconds to milliseconds by multiplying by 1000 + // Convert the microseconds to milliseconds by dividing by 1000 +} + +static void +_log_buf(c3_y* buf_y, c3_w len_w) +{ + for( c3_w i_w = 0; i_w < len_w; i_w++ ) { + fprintf(stderr, "%02x", buf_y[i_w]); + } + fprintf(stderr, "\r\n"); +} + + +static void +_log_gage(u3_gage* gag_u) +{ + u3l_log("gauge"); + u3l_log("rtt: %f", ((double)gag_u->rtt_w / 1000)); + u3l_log("rto: %f", ((double)gag_u->rto_w / 1000)); + u3l_log("rttvar: %f", ((double)gag_u->rtv_w / 1000)); + u3l_log("cwnd: %u", gag_u->wnd_w); + u3l_log("cwnd fraction: %f", gag_u->wnf_w / (float)gag_u->wnd_w ); + u3l_log("ssthresh: %u", gag_u->sst_w); + u3l_log("counter: %u", gag_u->con_w); + //u3l_log("algorithm: %s", gag_u->alg_c); +} + +static void +_log_lane(u3_lane* lan_u) +{ + u3l_log("xmas: lane (%s,%u)", u3r_string(u3dc("scot", c3__if, u3i_word(lan_u->pip_w))), lan_u->por_s); +} + + +static void _log_peer(u3_peer* per_u) +{ + if ( per_u == NULL ) { + u3l_log("NULL peer"); + return; + } + u3l_log("dir"); + _log_lane(&per_u->dir_u); + u3l_log("ind"); + _log_lane(&per_u->ind_u); + u3l_log("galaxy: %s", u3r_string(u3dc("scot", 'p', per_u->imp_s))); +} + +static void +_log_czar_info(u3_czar_info* zar_u) +{ + { + u3_noun nam = u3dc("scot", 'p', zar_u->imp_y); + u3l_log("czar: %s", u3r_string(nam)); + u3_noun pip = u3dc("scot", c3__if, zar_u->pip_w); + u3l_log("IP: %s", u3r_string(pip)); + u3l_log("time: %" PRIu64, (c3_d)zar_u->tim_t); + u3l_log("dns: %s", zar_u->dns_c != NULL ? zar_u->dns_c : "NO DNS"); + u3l_log("pending: %u", u3r_word(0, u3do("lent", zar_u->pen))); + } +} + +static void +_log_pend_req(u3_pend_req* req_u) +{ + if( req_u == NULL ) { + u3l_log("pending request was NULL"); + return; + } + u3l_log("have: %u", req_u->len_w); + u3l_log("next: %u", req_u->nex_w); + u3l_log("total: %u", req_u->tot_w); + u3l_log("gage: %c", req_u->gag_u == NULL ? 'n' : 'y'); + //u3l_log("timer in: %" PRIu64 " ms", uv_timer_get_due_in(&req_u->tim_u)); +} + +static c3_d +_get_now_micros() +{ + struct timeval tim_u; + gettimeofday(&tim_u, NULL); + return (tim_u.tv_sec * 1000000) + tim_u.tv_usec; +} + +static c3_d +_abs_dif(c3_d ayy_d, c3_d bee_d) +{ + return ayy_d > bee_d ? ayy_d - bee_d : bee_d - ayy_d; +} + +static c3_d +_clamp_rto(c3_d rto_d) { + return c3_min(c3_max(rto_d, 200000), 25000000); +} + +static c3_c* +_xmas_czar_dns(c3_y imp_y, c3_c* zar_c) +{ + u3_noun nam = u3dc("scot", 'p', imp_y); + c3_c* nam_c = u3r_string(nam); + c3_w len_w = 3 + strlen(nam_c) + strlen(zar_c); + u3_assert(len_w <= 256); + c3_c* dns_c = c3_calloc(len_w); + + c3_i sas_i = snprintf(dns_c, len_w, "%s.%s.", nam_c + 1, zar_c); + u3_assert(sas_i <= 255); + + c3_free(nam_c); + u3z(nam); + + return dns_c; +} + + +/* u3_xmas_encode_path(): produce buf_y as a parsed path +*/ +u3_noun +u3_xmas_encode_path(c3_w len_w, c3_y* buf_y) +{ + u3_noun pro; + u3_noun* lit = &pro; + + { + u3_noun* hed; + u3_noun* tel; + c3_y* fub_y = buf_y; + c3_y car_y; + c3_w tem_w; + u3i_slab sab_u; + + while ( len_w-- ) { + car_y = *buf_y++; + if ( len_w == 0 ) { + buf_y++; + car_y = 47; + } + + if ( 47 == car_y ) { + tem_w = buf_y - fub_y - 1; + u3i_slab_bare(&sab_u, 3, tem_w); + sab_u.buf_w[sab_u.len_w - 1] = 0; + memcpy(sab_u.buf_y, fub_y, tem_w); + + *lit = u3i_defcons(&hed, &tel); + *hed = u3i_slab_moot(&sab_u); + lit = tel; + fub_y = buf_y; + } + } + } + + *lit = u3_nul; + + return pro; +} + +static void +_xmas_free_pict(u3_xmas_pict* pic_u) +{ + xmas_free_pact(&pic_u->pac_u); + c3_free(pic_u); +} + +static u3_atom +_dire_etch_ud(c3_d num_d) +{ + c3_y hun_y[26]; + c3_y* buf_y = u3s_etch_ud_smol(num_d, hun_y); + c3_w dif_w = (c3_p)buf_y - (c3_p)hun_y; + return u3i_bytes(26 - dif_w, buf_y); // XX known-non-null +} + +/* _xmas_request_key(): produce key for request hashtable sam_u->req_p from nam_u +*/ +u3_noun _xmas_request_key(u3_xmas_name* nam_u) +{ + u3_noun pax = u3_xmas_encode_path(nam_u->pat_s, (c3_y*)nam_u->pat_c); + u3_noun res = u3nt(u3i_chubs(2, nam_u->her_d), u3i_word(nam_u->rif_w), pax); + return res; +} + +static void _init_gage(u3_gage* gag_u) +{ + gag_u->rto_w = 1000000; + gag_u->rtt_w = 1000000; + gag_u->rtv_w = 1000000; + gag_u->con_w = 0; + gag_u->wnd_w = 1; + gag_u->sst_w = 10000; +} + + +/* u3_xmas_encode_lane(): serialize lane to noun +*/ +static u3_noun +u3_xmas_encode_lane(u3_lane lan_u) { + // [%if ip=@ port=@] + return u3nt(c3__if, u3i_word(lan_u.pip_w), lan_u.por_s); +} + +// lane cache is (map [lane @p] lane-info) +// +static u3_noun +_xmas_lane_key(c3_d her_d[2], u3_lane* lan_u) +{ + return u3nc(u3i_chubs(2,her_d), u3_xmas_encode_lane(*lan_u)); +} + +/* RETAIN +*/ +static u3_gage* +_xmas_get_lane_raw(u3_xmas* sam_u, u3_noun key) +{ + u3_gage* ret_u = NULL; + u3_weak res = u3h_git(sam_u->lan_p, key); + + if ( res != u3_none && res != u3_nul ) { + ret_u = u3to(u3_gage, res); + } + + return ret_u; +} + +/* _xmas_get_lane(): get lane +*/ +static u3_gage* +_xmas_get_lane(u3_xmas* sam_u, c3_d her_d[2], u3_lane* lan_u) { + u3_noun key =_xmas_lane_key(her_d, lan_u); + u3_gage* ret_u = _xmas_get_lane_raw(sam_u, key); + u3z(key); + return ret_u; +} + +/* _xmas_put_lane(): put lane state in state + * + * uses same copying trick as _xmas_put_request() +*/ +static void +_xmas_put_lane(u3_xmas* sam_u, c3_d her_d[2], u3_lane* lan_u, u3_gage* gag_u) +{ + u3_noun key = _xmas_lane_key(her_d, lan_u); + u3_gage* old_u = _xmas_get_lane_raw(sam_u, key); + u3_gage* new_u = gag_u; + + if ( old_u == NULL ) { + new_u = u3a_calloc(sizeof(u3_gage),1); + memcpy(new_u, gag_u, sizeof(u3_gage)); + } else { + new_u = old_u; + memcpy(new_u, gag_u, sizeof(u3_gage)); + } + + u3_noun val = u3of(u3_gage, new_u); + u3h_put(sam_u->lan_p, key, val); + u3z(key); +} + +static void +_xmas_del_request(u3_xmas* sam_u, u3_xmas_name* nam_u) { + u3_noun key = _xmas_request_key(nam_u); + + u3_weak req = u3h_get(sam_u->req_p, key); + if ( req == u3_none ) { + u3z(key); + return; + } + u3_pend_req* req_u = u3to(u3_pend_req, req); + // u3l_log("wat_u %p", req_u->wat_u); + // u3l_log("was_u buf %p", req_u->was_u.buf_y); + uv_timer_stop(&req_u->tim_u); + _xmas_free_pict(req_u->pic_u); + c3_free(req_u->wat_u); + vec_free(&req_u->mis_u); + c3_free(req_u->dat_y); + blake_bao_free(req_u->bao_u); + u3h_del(sam_u->req_p, key); + u3a_free(req_u); + u3z(key); +} + +// congestion control update +static void _xmas_handle_ack(u3_gage* gag_u, u3_pact_stat* pat_u) +{ + + gag_u->con_w++; + + c3_d now_d = _get_now_micros(); + c3_d rtt_d = now_d < pat_u->sen_d ? 0 : now_d - pat_u->sen_d; + + c3_d err_d = _abs_dif(rtt_d, gag_u->rtt_w); + + gag_u->rtt_w = (rtt_d + (gag_u->rtt_w * 7)) >> 3; + gag_u->rtv_w = (err_d + (gag_u->rtv_w * 7)) >> 3; + gag_u->rto_w = _clamp_rto(gag_u->rtt_w + (4*gag_u->rtv_w)); + + if ( gag_u->wnd_w < gag_u->sst_w ) { + gag_u->wnd_w++; + } else if ( gag_u->wnd_w <= ++gag_u->wnf_w ) { + gag_u->wnd_w++; + gag_u->wnf_w = 0; + } +} + +/* + * _xmas_req_get_cwnd(): produce packets to send + * + * saves next fragment number and preallocated pact into the passed pointers. + * Will not do so if returning 0 +*/ +static c3_w +_xmas_req_get_cwnd(u3_pend_req* req_u) +{ + c3_w res_w = 0; + + if ( req_u->tot_w == 0 || req_u->gag_u == NULL ) { + u3l_log("shouldn't happen"); + _log_pend_req(req_u); + u3_assert(0); + return 1; + } + + c3_w liv_w = bitset_wyt(&req_u->was_u); + if ( req_u->nex_w == req_u->tot_w ) { + return 0; + } + + c3_w rem_w = req_u->tot_w - req_u->nex_w + 1; + return c3_min(rem_w, req_u->gag_u->wnd_w - liv_w); +} + +/* _xmas_req_pact_sent(): mark packet as sent +** +*/ +static void +_xmas_req_pact_resent(u3_pend_req* req_u, u3_xmas_name* nam_u) +{ + c3_d now_d = _get_now_micros(); + // if we dont have pending request noop + if ( NULL == req_u ) { + return; + } + + req_u->wat_u[nam_u->fra_w].sen_d = now_d; + req_u->wat_u[nam_u->fra_w].tie_y++; +} + +/* _xmas_req_pact_sent(): mark packet as sent +** after 1-RT first packet is handled in _xmas_req_pact_init() +*/ +static void +_xmas_req_pact_sent(u3_pend_req* req_u, u3_xmas_name* nam_u) +{ + c3_d now_d = _get_now_micros(); + // if we already have pending request + if ( NULL != req_u ) { + if( req_u->nex_w == nam_u->fra_w ) { + req_u->nex_w++; + } + // TODO: optional assertions? + req_u->wat_u[nam_u->fra_w] = (u3_pact_stat){now_d, 0, 1, 0 }; + bitset_put(&req_u->was_u, nam_u->fra_w); + } else { + u3l_log("xmas: no req for sent"); + return; + } + + if ( req_u->lef_w != 0 && c3n == bitset_has(&req_u->was_u, req_u->lef_w) ) { + while ( req_u->lef_w++ < req_u->tot_w ) { + if ( c3y == bitset_has(&req_u->was_u, req_u->lef_w) ) { + break; + } + } + } +} + + +/* _ames_czar_port(): udp port for galaxy. +*/ +static c3_s +_ames_czar_port(c3_y imp_y) +{ + if ( c3n == u3_Host.ops_u.net ) { + return 31337 + imp_y; + } + else { + return 13337 + imp_y; + } +} + + +/* _ames_alloc(): libuv buffer allocator. +*/ +static void +_ames_alloc(uv_handle_t* had_u, + size_t len_i, + uv_buf_t* buf + ) +{ + // we allocate 2K, which gives us plenty of space + // for a single ames packet (max size 1060 bytes) + // + void* ptr_v = c3_malloc(4096); + *buf = uv_buf_init(ptr_v, 4096); +} + +/* u3_xmas_decode_lane(): deserialize noun to lane; 0.0.0.0:0 if invalid +*/ +static u3_lane +u3_xmas_decode_lane(u3_atom lan) { + u3_lane lan_u; + c3_d lan_d; + + if ( c3n == u3r_safe_chub(lan, &lan_d) || (lan_d >> 48) != 0 ) { + return (u3_lane){0, 0}; + } + + u3z(lan); + + lan_u.pip_w = (c3_w)lan_d; + lan_u.por_s = (c3_s)(lan_d >> 32); + // convert incoming localhost to outgoing localhost + // + lan_u.pip_w = ( 0 == lan_u.pip_w ) ? 0x7f000001 : lan_u.pip_w; + + return lan_u; +} + +// END plagariasm zone +// +// +// +// +// +// +static void _xmas_free_seal(u3_seal* sel_u) +{ + c3_free(sel_u->buf_y); + c3_free(sel_u); +} + +static u3_noun _xmas_get_now() { + struct timeval tim_u; + gettimeofday(&tim_u, 0); + u3_noun res = u3_time_in_tv(&tim_u); + return res; +} + + + + +static void +_xmas_send_cb(uv_udp_send_t* req_u, c3_i sas_i) +{ + u3_seal* sel_u = (u3_seal*)req_u; + u3_xmas* sam_u = sel_u->sam_u; + + if ( sas_i ) { + u3l_log("xmas: send fail_async: %s", uv_strerror(sas_i)); + //sam_u->fig_u.net_o = c3n; + } + else { + //sam_u->fig_u.net_o = c3y; + } + + _xmas_free_seal(sel_u); +} + +static void _xmas_send_buf(u3_xmas* sam_u, u3_lane lan_u, c3_y* buf_y, c3_w len_w) +{ + u3_seal* sel_u = c3_calloc(sizeof(*sel_u)); + // this is wrong, need to calloc & memcpy + sel_u->buf_y = buf_y; + sel_u->len_w = len_w; + sel_u->sam_u = sam_u; + struct sockaddr_in add_u; + + memset(&add_u, 0, sizeof(add_u)); + add_u.sin_family = AF_INET; + c3_w pip_w = c3n == u3_Host.ops_u.net ? lan_u.pip_w : 0x7f000001; + c3_s por_s = lan_u.por_s; + + add_u.sin_addr.s_addr = htonl(pip_w); + add_u.sin_port = htons(por_s); + +#ifdef XMAS_DEBUG + c3_c* sip_c = inet_ntoa(add_u.sin_addr); + // u3l_log("xmas: sending packet (%s,%u)", sip_c, por_s); +#endif + + uv_buf_t buf_u = uv_buf_init((c3_c*)buf_y, len_w); + + c3_i sas_i = uv_udp_send(&sel_u->snd_u, + &sam_u->wax_u, + &buf_u, 1, + (const struct sockaddr*)&add_u, + _xmas_send_cb); + + if ( sas_i ) { + u3l_log("ames: send fail_sync: %s", uv_strerror(sas_i)); + /*if ( c3y == sam_u->fig_u.net_o ) { + //sam_u->fig_u.net_o = c3n; + }*/ + _xmas_free_seal(sel_u); + } +} + + + +static void _xmas_send(u3_xmas_pict* pic_u, u3_lane* lan_u) +{ + u3_xmas* sam_u = pic_u->sam_u; + + c3_y* buf_y = c3_calloc(PACT_SIZE); + c3_w siz_w = xmas_etch_pact(buf_y, &pic_u->pac_u); + + _xmas_send_buf(sam_u, *lan_u, buf_y, siz_w); +} + + +static void +_try_resend(u3_pend_req* req_u) +{ + u3_xmas* sam_u = req_u->pic_u->sam_u; + u3_lane* lan_u = &req_u->lan_u; + c3_o los_o = c3n; + if ( req_u->tot_w == 0 || req_u->ack_w <= REORDER_THRESH ) { + return; + } + c3_w ack_w = req_u->ack_w - REORDER_THRESH; + c3_d now_d = _get_now_micros(); + for ( int i = req_u->lef_w; i < ack_w; i++ ) { + if ( c3y == bitset_has(&req_u->was_u, i) ) { + req_u->pic_u->pac_u.pek_u.nam_u.fra_w = i; + if ( req_u->wat_u[i].tie_y == 1 ) { + u3l_log("fast resend %u", i); + los_o = c3y; + c3_y* buf_y = c3_calloc(PACT_SIZE); + req_u->pic_u->pac_u.pek_u.nam_u.fra_w = i; + c3_w siz_w = xmas_etch_pact(buf_y, &req_u->pic_u->pac_u); + if ( siz_w == 0 ) { + u3l_log("failed to etch"); + u3_assert( 0 ); + } + // TODO: better route management + _xmas_send_buf(sam_u, *lan_u, buf_y, siz_w); + _xmas_req_pact_resent(req_u, &req_u->pic_u->pac_u.pek_u.nam_u); + + } else if ( (now_d - req_u->wat_u[i].sen_d) > req_u->gag_u->rto_w ) { + los_o = c3y; + c3_y* buf_y = c3_calloc(PACT_SIZE); + req_u->pic_u->pac_u.pek_u.nam_u.fra_w = i; + u3l_log("slow resending %u ", i); + c3_w siz_w = xmas_etch_pact(buf_y, &req_u->pic_u->pac_u); + if( siz_w == 0 ) { + u3l_log("failed to etch"); + u3_assert( 0 ); + } + // TODO: better route management + _xmas_send_buf(sam_u, *lan_u, buf_y, siz_w); + _xmas_req_pact_resent(req_u, &req_u->pic_u->pac_u.pek_u.nam_u); + } + } + } + + if ( c3y == los_o ) { + req_u->gag_u->sst_w = (req_u->gag_u->wnd_w / 2) + 1; + req_u->gag_u->wnd_w = req_u->gag_u->sst_w; + req_u->gag_u->rto_w = _clamp_rto(req_u->gag_u->rto_w * 2); + } +} + +/* _xmas_packet_timeout(): callback for packet timeout +*/ +static void +_xmas_packet_timeout(uv_timer_t* tim_u) { + u3_pend_req* req_u = (u3_pend_req*)tim_u->data; + u3l_log("%u packet timed out", req_u->old_w); + _try_resend(req_u); +} + +static void +_update_oldest_req(u3_pend_req *req_u, u3_gage* gag_u) +{ + if( req_u->tot_w == 0 || req_u->len_w == req_u->tot_w ) { + return; + } + // scan in flight packets, find oldest + c3_w idx_w = req_u->lef_w; + c3_d now_d = _get_now_micros(); + c3_d wen_d = now_d; + for ( c3_w i = req_u->lef_w; i < req_u->nex_w; i++ ) { + // u3l_log("fra %u (%u)", i, __LINE__); + if ( c3y == bitset_has(&req_u->was_u, i) && + wen_d > req_u->wat_u[i].sen_d + ) { + wen_d = req_u->wat_u[i].sen_d; + idx_w = i; + } + } + if ( now_d == wen_d ) { +#ifdef XMAS_DEBUG + u3l_log("failed to find new oldest"); +#endif + } + req_u->old_w = idx_w; + req_u->tim_u.data = req_u; + c3_d gap_d = now_d -req_u->wat_u[idx_w].sen_d; + uv_timer_start(&req_u->tim_u, _xmas_packet_timeout, (gag_u->rto_w - gap_d) / 1000, 0); +} + +static void _xmas_free_misord_buf(u3_misord_buf* buf_u) +{ + c3_free(buf_u->fra_y); + if ( buf_u->par_u != NULL ) { + c3_free(buf_u->par_u); + } + c3_free(buf_u); +} + +static bao_ingest_result +_xmas_burn_misorder_queue(u3_pend_req* req_u) +{ + c3_w wan_w = req_u->bao_u->con_w; + c3_w len_w; + c3_o fon_o; + bao_ingest_result res_y = BAO_GOOD; + while ( (len_w = vec_len(&req_u->mis_u)) != 0 ) { + fon_o = c3n; + for (int i = 0; i < len_w; i++) { + u3_misord_buf* buf_u = (u3_misord_buf*)req_u->mis_u.vod_p[i]; + if ( buf_u->num_w == wan_w ) { + fon_o = c3y; + if ( BAO_GOOD != (res_y = blake_bao_verify(req_u->bao_u, buf_u->fra_y, buf_u->len_w, buf_u->par_u))) { + return res_y; + } else { + _xmas_free_misord_buf((u3_misord_buf*)vec_pop(&req_u->mis_u, i)); + break; + } + } + } + wan_w++; + if ( c3n == fon_o ) { + break; + } + } + return res_y; +} + +/* _xmas_req_pact_done(): mark packet as done, returning if we should continue +*/ +static u3_pend_req* +_xmas_req_pact_done(u3_xmas* sam_u, + u3_pend_req* req_u, + u3_xmas_name *nam_u, + u3_xmas_data* dat_u, + u3_lane* lan_u) +{ + c3_d now_d = _get_now_micros(); // XX use? + + u3_gage* gag_u = _xmas_get_lane(sam_u, nam_u->her_d, lan_u); + req_u->gag_u = gag_u; + + // first we hear from lane + if ( gag_u == NULL ) { + gag_u = alloca(sizeof(u3_gage)); + memset(gag_u, 0, sizeof(u3_gage)); + _init_gage(gag_u); + } + + req_u->lan_u = *lan_u; + + c3_w siz_w = (1 << (nam_u->boq_y - 3)); + // First packet received, instantiate request fully + + if ( dat_u->tot_w <= nam_u->fra_w ) { + XMAS_LOG(STRANGE); + // XX: is this sufficient to drop whole request + return NULL; + } + + // received duplicate + if ( nam_u->fra_w != 0 && c3n == bitset_has(&req_u->was_u, nam_u->fra_w) ) { + XMAS_LOG(DUPE); + req_u->wat_u[nam_u->fra_w].dup_y++; + return NULL; + } + + bitset_del(&req_u->was_u, nam_u->fra_w); + if ( nam_u->fra_w > req_u->ack_w ) { + req_u->ack_w = nam_u->fra_w; + } + if ( nam_u->fra_w != 0 && req_u->wat_u[nam_u->fra_w].tie_y != 1 ) { +#ifdef XMAS_DEBUG + u3l_log("received retry %u", nam_u->fra_w); +#endif + } + + req_u->len_w++; + if ( req_u->lef_w == nam_u->fra_w ) { + req_u->lef_w++; + } + + blake_pair* par_u = NULL; + if ( dat_u->aum_u.typ_e == AUTH_NEXT ) { + // needs to be heap allocated bc will be saved if misordered + par_u = c3_calloc(sizeof(blake_pair)); + memcpy(par_u->sin_y, dat_u->aup_u.has_y[0], BLAKE3_OUT_LEN); + memcpy(par_u->dex_y, dat_u->aup_u.has_y[1], BLAKE3_OUT_LEN); + } + + c3_y ver_y; + // TODO: move to bottom + if ( req_u->bao_u->con_w != nam_u->fra_w ) { + // TODO: queue packet + u3_misord_buf* buf_u = c3_calloc(sizeof(u3_misord_buf)); + buf_u->fra_y = c3_calloc(dat_u->len_w); + buf_u->len_w = dat_u->len_w; + memcpy(buf_u->fra_y, dat_u->fra_y, dat_u->len_w); + buf_u->par_u = par_u; + buf_u->num_w = nam_u->fra_w; + vec_append(&req_u->mis_u, buf_u); + } else if ( BAO_GOOD != (ver_y = blake_bao_verify(req_u->bao_u, dat_u->fra_y, dat_u->len_w, par_u)) ) { + c3_free(par_u); + // TODO: do we drop the whole request on the floor? + XMAS_LOG(AUTH); + return NULL; + } else if ( vec_len(&req_u->mis_u) != 0 + && BAO_GOOD != (ver_y = _xmas_burn_misorder_queue(req_u))) { + c3_free(par_u); + XMAS_LOG(AUTH) + return NULL; + } else { + c3_free(par_u); + } + + // handle gauge update + _xmas_handle_ack(gag_u, &req_u->wat_u[nam_u->fra_w]); + + + memcpy(req_u->dat_y + (siz_w * nam_u->fra_w), dat_u->fra_y, dat_u->len_w); + + _try_resend(req_u); + + _update_oldest_req(req_u, gag_u); + + // _xmas_put_request(sam_u, nam_u, req_u); + // _xmas_put_lane(sam_u, nam_u->her_d, lan_u, gag_u); + return req_u; +} + + + + +static u3_lane +_realise_lane(u3_noun lan) { + u3_lane lan_u = {0}; + + if ( c3y == u3a_is_cat(lan) ) { + // XX groace and wrong + // + if ( lan >= 256 ) { + u3m_p("big lane", lan); + lan &= 0xff; + } + + if ( (c3n == u3_Host.ops_u.net) ) { + lan_u.pip_w = 0x7f000001 ; + lan_u.por_s = _ames_czar_port(lan); + } + } + else { + u3_noun pip, por; + + if ( (c3y == u3r_pq(lan, c3__if, &pip, &por)) + && (c3y == u3r_safe_word(pip, &lan_u.pip_w)) + && (c3y == u3a_is_cat(por)) + && (por <= 0xFFFF) ) + { + lan_u.por_s = por; + } + else { + u3m_p("inscrutable lane", lan); + } + + u3z(lan); + } + + return lan_u; +} + +static c3_o +_xmas_rout_bufs(u3_xmas* sam_u, c3_y* buf_y, c3_w len_w, u3_noun las) +{ + c3_o suc_o = c3n; + u3_noun lan, t = las; + while ( t != u3_nul ) { + u3x_cell(t, &lan, &t); + u3_lane lan_u = _realise_lane(u3k(lan)); + #ifdef XMAS_DEBUG + u3l_log("sending to ip: %x, port: %u", lan_u.pip_w, lan_u.por_s); + + #endif /* ifdef XMAS_DEBUG + u3l_log("sending to ip: %x, port: %u", lan_u.pip_w, lan_u.por_s); */ + if ( lan_u.por_s == 0 ) { + u3l_log("xmas: failed to realise lane"); + } else { + c3_y* sen_y = c3_calloc(len_w); + memcpy(sen_y, buf_y, len_w); + _xmas_send_buf(sam_u, lan_u, sen_y, len_w); + } + } + // u3z(las); + return suc_o; +} + +static void +_xmas_timer_cb(uv_timer_t* tim_u) { + u3_pend_req* req_u = tim_u->data; + _try_resend(req_u); +} + +static void +_xmas_czar_here(u3_czar_info* imp_u, time_t now_t, struct sockaddr_in* add_u) +{ + u3_xmas* sam_u = imp_u->sam_u; + c3_y imp_y = imp_u->imp_y; + c3_w pip_w = ntohl(add_u->sin_addr.s_addr); + + if ( imp_u->pip_w != pip_w ) { + u3_noun nam = u3dc("scot", c3__if, u3i_word(pip_w)); + c3_c* nam_c = u3r_string(nam); + + u3l_log("xmas: czar %s: ip %s", imp_u->dns_c, nam_c); + + c3_free(nam_c); + u3z(nam); + } + imp_u->pip_w = pip_w; + imp_u->tim_t = now_t; + + u3_noun pac, t = imp_u->pen; + + while ( t != u3_nul ) { + u3x_cell(t, &pac, &t); + c3_w len_w = u3r_met(3,pac); + c3_y* buf_y = c3_calloc(len_w); + u3r_bytes(0, len_w, buf_y, pac); + u3_lane lan_u = (u3_lane){pip_w, _ames_czar_port(imp_y)}; + _xmas_send_buf(sam_u, lan_u, buf_y, len_w); + } + u3z(imp_u->pen); + imp_u->pen = u3_nul; +} + +static void +_xmas_czar_gone(u3_xmas* sam_u, c3_i sas_i, c3_y imp_y, time_t now_t) +{ + u3_czar_info* imp_u = &sam_u->imp_u[imp_y]; + imp_u->tim_t = now_t; + u3l_log("xmas: %s", uv_strerror(sas_i)); +} + +static void +_xmas_czar_cb(uv_getaddrinfo_t* adr_u, c3_i sas_i, struct addrinfo* aif_u) +{ + u3_czar_info* imp_u = (u3_czar_info*)adr_u->data; + c3_y imp_y = imp_u->imp_y; + u3_xmas* sam_u = imp_u->sam_u; + time_t now_t = time(0); + + if ( 0 == sas_i ) { + // XX: lifetimes for addrinfo, ames does something funny + _xmas_czar_here(imp_u, now_t, (struct sockaddr_in*)aif_u->ai_addr); + } else { + _xmas_czar_gone(sam_u, sas_i, imp_y, now_t); + } + + c3_free(adr_u); + uv_freeaddrinfo(aif_u); + +} + + + +static void +_xmas_resolve_czar(u3_xmas* sam_u, c3_y imp_y, u3_noun pac) +{ + u3_assert( c3y == u3_Host.ops_u.net ); + u3_czar_info* imp_u = &sam_u->imp_u[imp_y]; + time_t now_t = time(0); + time_t wen_t = imp_u->tim_t; + if ( ((now_t - wen_t) < 300) ) { + // XX: confirm validity of drop + return; + } + if ( pac != u3_nul && u3_nul != imp_u->pen ) { + // already pending, add to queue + imp_u->pen = u3nc(pac, imp_u->pen); + return; + } + if ( pac != u3_nul ) { + imp_u->pen = u3nc(pac, imp_u->pen); + } + + if ( !sam_u->dns_c ) { + u3l_log("xmas: no galaxy domain"); + return; + } + imp_u->dns_c = _xmas_czar_dns(imp_y, sam_u->dns_c); + { + uv_getaddrinfo_t* adr_u = c3_calloc(sizeof(*adr_u)); + c3_i sas_i; + adr_u->data = imp_u; + struct addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + if ( 0 != (sas_i = uv_getaddrinfo(u3L, adr_u, _xmas_czar_cb, imp_u->dns_c, 0, &hints))) { + time_t now_t = time(0); + _xmas_czar_gone(sam_u, sas_i, imp_y, now_t); + return; + } + } + + +} + +static u3_noun +_xmas_queue_czar(u3_xmas* sam_u, u3_noun las, u3_noun pac) +{ + las = u3do("flop", las); + u3_noun lan, t = las; + u3_noun res = u3_nul; + time_t now_t = time(0); + + while ( t != u3_nul ) { + u3x_cell(t, &lan, &t); + if ( (c3y == u3a_is_cat(lan) && lan < 256 ) ) { + u3_czar_info* imp_u = &sam_u->imp_u[lan]; + + if ( 0 != imp_u->pip_w ) { + res = u3nc(u3nt(c3__if, u3i_word(imp_u->pip_w), _ames_czar_port(lan)), res); + } + if ( c3y == u3_Host.ops_u.net ) { + _xmas_resolve_czar(sam_u, lan, u3k(pac)); + } + } else { + res = u3nc(u3k(lan), res); + } + } + u3z(las); + u3z(pac); + return res; +} + +static void +_init_peer(u3_xmas* sam_u, u3_peer* per_u) +{ + per_u->sam_u = sam_u; + + per_u->imp_s = 256; + per_u->dir_u = (u3_lane){0,0}; + per_u->ind_u = (u3_lane){0,0}; + per_u->las_u = (u3_peer_last){0,0}; +} + +// TODO: all the her_p hashtable functions are not refcounted properly + +static u3_peer* +_xmas_get_peer_raw(u3_xmas* sam_u, u3_noun her) +{ + u3_peer* ret_u = NULL; + u3_weak res = u3h_git(sam_u->her_p, her); + + if ( res != u3_none && res != u3_nul ) { + ret_u = u3to(u3_peer, res); + } + + u3z(her); + return ret_u; + +} +/* + * RETAIN + */ +static u3_peer* +_xmas_get_peer(u3_xmas* sam_u, c3_d her_d[2]) +{ + return _xmas_get_peer_raw(sam_u, u3i_chubs(2, her_d)); +} + + + +/* + */ +static void +_xmas_put_peer_raw(u3_xmas* sam_u, u3_noun her, u3_peer* per_u) +{ + u3_peer* old_u = _xmas_get_peer_raw(sam_u, u3k(her)); + u3_peer* new_u = NULL; + + if ( old_u == NULL ) { + new_u = u3a_calloc(sizeof(u3_peer),1); + memcpy(new_u, per_u, sizeof(u3_peer)); + } else if ( new_u != old_u ) { + new_u = old_u; + memcpy(new_u, per_u, sizeof(u3_peer)); + } + + u3_noun val = u3of(u3_peer, new_u); + u3h_put(sam_u->her_p, her, val); + u3z(her); +} + +static void +_xmas_put_peer(u3_xmas* sam_u, c3_d her_d[2], u3_peer* per_u) +{ + _xmas_put_peer_raw(sam_u, u3i_chubs(2, her_d), per_u); +} + + +static u3_lane +_xmas_get_direct_lane_raw(u3_xmas* sam_u, u3_noun her) +{ + if ( c3y == u3a_is_cat(her) && her < 256 ) { + c3_s por_s = _ames_czar_port(her); + return (u3_lane){sam_u->imp_u[her].pip_w, por_s}; + } + u3_peer* per_u = _xmas_get_peer_raw(sam_u, her); + if ( NULL == per_u ) { + return (u3_lane){0,0}; + } + return per_u->dir_u; +} + +static u3_lane +_xmas_get_direct_lane(u3_xmas* sam_u, c3_d her_d[2]) +{ + return _xmas_get_direct_lane_raw(sam_u, u3i_chubs(2, her_d)); +} + + +static u3_lane +_xmas_get_indirect_lane(u3_xmas* sam_u, u3_noun her, u3_noun lan) +{ + if ( c3y == u3a_is_cat(her) && her < 256 ) { + c3_s por_s = _ames_czar_port(her); + return (u3_lane){sam_u->imp_u[her].pip_w, por_s}; + } + u3_peer* per_u = _xmas_get_peer_raw(sam_u, her); + if ( NULL == per_u ) { + return (u3_lane){0,0}; + } + return per_u->ind_u; +} + + +/* + * RETAIN + */ +static c3_o +_xmas_add_galaxy_pend(u3_xmas* sam_u, u3_noun her, u3_noun pen) +{ + u3_weak old = u3h_get(sam_u->her_p, her); + u3_noun pes = u3_nul; + u3_noun wat; + if ( u3_none != old ) { + if ( u3h(old) == XMAS_CZAR ) { + u3x_cell(u3t(old), &pes, &wat); + u3z(old); + } else { + u3l_log("xmas: attempted to resolve resolved czar"); + u3z(old); + return c3n; + } + } + u3_noun val = u3nc(u3nc(u3k(pen), u3k(pes)), c3y); + u3h_put(sam_u->her_p, her, val); + u3z(val); + return _(wat); +} + +static u3_noun +_name_to_scry(u3_xmas_name* nam_u) +{ + u3_noun rif = _dire_etch_ud(nam_u->rif_w); + u3_noun boq = _dire_etch_ud(nam_u->boq_y); + u3_noun fag = _dire_etch_ud(nam_u->fra_w); + u3_noun pax = u3_xmas_encode_path(nam_u->pat_s, (c3_y*)nam_u->pat_c); + + u3_noun wer = nam_u->nit_o == c3y + ? u3nc(c3__init, pax) + : u3nt(nam_u->aut_o == c3y ? c3__auth : c3__data, fag, pax); + + u3_noun res = u3nc(c3__mess, u3nq(rif, c3__pact, boq, u3nc(c3__etch, wer))); + + return res; +} + +/* + * RETAIN: feat, cash, and pint + */ + +typedef struct _feat_key { + u3_noun key; +} _feat_key; + +static _feat_key +_xmas_feat_key(u3_xmas_name* nam_u) +{ + return (_feat_key){ _xmas_request_key(nam_u) }; +} + +static u3_pend_req* +_xmas_feat_git(u3_xmas* sam_u, _feat_key fek_u) +{ + u3_weak res = u3h_git(sam_u->req_p, fek_u.key); + + if ( u3_none == res ) { + return NULL; + } + else { + return u3to(u3_pend_req, res); + } +} + +static void +_xmas_feat_put(u3_xmas* sam_u, _feat_key fek_u, u3_pend_req* req_u) +{ + // XX assert pointer in loom + // + u3_assert(req_u); + u3_noun val = u3of(u3_pend_req, req_u); + u3h_put(sam_u->req_p, fek_u.key, val); +} + +typedef struct _pact_key { + u3_noun key; +} _pact_key; + +static _pact_key +_xmas_pact_key(u3_xmas_name* nam_u) +{ + return (_pact_key){ + .key = u3nc(u3i_chubs(2, nam_u->her_d), + _name_to_scry(nam_u)) + }; +} + +static u3_weak +_xmas_cash_git(u3_xmas* sam_u, _pact_key pek_u) +{ + return u3h_git(sam_u->cac_p, pek_u.key); +} + +static void +_xmas_cash_put(u3_xmas* sam_u, _pact_key pek_u, u3_atom pac) +{ + return u3h_put(sam_u->cac_p, pek_u.key, pac); +} + +static void +_xmas_cash_put_safe(u3_xmas* sam_u, + _pact_key pek_u, + u3_atom pac, + u3_weak val) +{ + if ( (u3_none != val ) + && (c3n == u3r_sing(pac, val)) ) + { + u3l_log("xmas: cache collision old=0x%x, new=0x%x", + u3r_mug(val), u3r_mug(val)); + // XX keep old? + } + + return _xmas_cash_put(sam_u, pek_u, pac); +} + +static u3_weak +_xmas_pint_git(u3_xmas* sam_u, _pact_key pek_u) +{ + return u3h_git(sam_u->pit_p, pek_u.key); +} + +static void +_xmas_pint_put(u3_xmas* sam_u, _pact_key pek_u, u3_noun val) +{ + return u3h_put(sam_u->pit_p, pek_u.key, val); +} + +static void +_xmas_pint_del(u3_xmas* sam_u, _pact_key pek_u) +{ + u3h_del(sam_u->pit_p, pek_u.key); +} + +static void +_xmas_pint_add(u3_xmas* sam_u, + _pact_key pek_u, + c3_o our_o, + u3_weak lan, + u3_weak val) +{ + u3_atom tim = u3i_chub(_get_now_micros()); + u3_noun new; + + // [first=@da last=@da our=? for=(set lane)] + // + if ( u3_none == val ) { + lan = ( u3_none == lan ) ? u3_nul : u3nt(lan, u3_nul, u3_nul); + new = u3nq(u3k(tim), tim, our_o, lan); + } + else { + u3_noun tel = u3t(u3t(val)); + u3_noun lis = u3t(tel); + c3_o old_o = u3h(tel); + + our_o = ( c3y == our_o ) ? our_o : old_o; + lis = ( u3_none == lan )? u3k(lis) : u3qdi_put(lis, lan); + + new = u3nq(u3k(u3h(val)), tim, our_o, lis); + } + + return _xmas_pint_put(sam_u, pek_u, new); +} + +static c3_w +_xmas_respond(u3_xmas_pict* req_u, c3_y** buf_y, u3_noun hit) +{ + c3_w len_w = u3r_met(3, hit); + + + *buf_y = c3_calloc(len_w); + u3r_bytes(0, len_w, *buf_y, hit); + + //u3z(hit); + return len_w; +} + +/* + */ +static void +_xmas_page_scry_cb(void* vod_p, u3_noun nun) +{ + u3_xmas_pict* pic_u = vod_p; + u3_xmas_pact* pac_u = &pic_u->pac_u; + u3_xmas_name* nam_u = &pac_u->pek_u.nam_u; // NB: works for all + u3_xmas* sam_u = pic_u->sam_u; + + u3_weak val = u3r_at(7, nun); + if ( u3_none == val ) { + // TODO: mark as dead + //u3z(nun); + u3l_log("xmas: path unbound"); + } + else { + _pact_key pek_u = _xmas_pact_key(nam_u); + u3_weak hit = _xmas_cash_git(sam_u, pek_u); + + if ( u3_none != hit ) { + u3l_log("xmas: page already cached"); + } + + _xmas_cash_put_safe(sam_u, pek_u, u3k(val), hit); + + hit = _xmas_pint_git(sam_u, pek_u); + + if ( u3_none == hit ) { + u3l_log("xmas: pit entry missing"); + } + else { + u3_noun tel = u3t(u3t(hit)); + u3_noun lis = u3t(tel); + c3_o our_o = u3h(tel); + u3_noun lan = u3qdi_tap(lis); + + if ( c3y == our_o ) { + u3l_log("xmas: strange self request"); + } + + c3_y* buf_y; + c3_w len_w = _xmas_respond(pic_u, &buf_y, u3k(val)); + _xmas_rout_bufs(sam_u, buf_y, len_w, lan); + + _xmas_pint_del(sam_u, pek_u); + } + + u3z(pek_u.key); + } + + u3z(nun); +} + +static void +_xmas_hear_bail(u3_ovum* egg_u, u3_noun lud) +{ + u3l_log("xmas: hear bail"); + c3_w len_w = u3qb_lent(lud); + u3l_log("len_w: %i", len_w); + if( len_w == 2 ) { + u3_pier_punt_goof("hear", u3k(u3h(lud))); + u3_pier_punt_goof("crud", u3k(u3h(u3t(lud)))); + } + u3_ovum_free(egg_u); +} + + +static void +_saxo_cb(void* vod_p, u3_noun nun) +{ + u3_peer* per_u = vod_p; + u3_weak sax = u3r_at(7, nun); + + if ( sax != u3_none ) { + u3_noun her = u3do("head", u3k(sax)); + u3_peer* new_u = _xmas_get_peer_raw(per_u->sam_u, u3k(her)); + if ( new_u != NULL ) { + per_u = new_u; + } + u3_xmas* sam_u = per_u->sam_u; + u3_noun gal = u3do("rear", u3k(sax)); + u3_assert( c3y == u3a_is_cat(gal) && gal < 256 ); + // both atoms guaranteed to be cats, bc we don't call unless forwarding + per_u->imp_s = gal; + _xmas_put_peer_raw(per_u->sam_u, her, per_u); + } + + u3z(nun); +} + +static void +_meet_peer(u3_xmas* sam_u, u3_peer* per_u, c3_d her_d[2]) +{ + c3_d now_d = _get_now_micros(); + per_u->las_u.son_d = now_d; + + u3_noun her = u3i_chubs(2, her_d); + u3_noun gan = u3nc(u3_nul, u3_nul); + u3_noun pax = u3nc(u3dc("scot", c3__p, her), u3_nul); + u3_pier_peek_last(sam_u->pir_u, gan, c3__j, c3__saxo, pax, per_u, _saxo_cb); +} + +static void +_hear_peer(u3_xmas* sam_u, u3_peer* per_u, u3_lane lan_u, c3_o dir_o) +{ + c3_d now_d = _get_now_micros(); + per_u->las_u.acc_d = now_d; + if ( c3y == dir_o ) { + per_u->dir_u = lan_u; + } else { + per_u->ind_u = lan_u; + } +} + +static void +_xmas_req_pact_next(u3_xmas* sam_u, u3_pend_req* req_u, u3_lane* lan_u) +{ + u3_assert(req_u); + + c3_w win_w = _xmas_req_get_cwnd(req_u); + u3_xmas_pict* nex_u = req_u->pic_u; + c3_w nex_w = req_u->nex_w; + if ( win_w != 0 ) { +#ifdef XMAS_DEBUG + u3l_log("continuing flow nex: %u, win: %u", nex_w, win_w); + u3l_log("in flight %u", bitset_wyt(&req_u->was_u)); +#endif + for ( int i = 0; i < win_w; i++ ) { + c3_y* buf_y = c3_calloc(PACT_SIZE); + c3_w fra_w = nex_w + i; + if ( fra_w >= req_u->tot_w ) { + break; + } + nex_u->pac_u.pek_u.nam_u.fra_w = nex_w + i; + c3_w siz_w = xmas_etch_pact(buf_y, &nex_u->pac_u); + if ( siz_w == 0 ) { + u3l_log("failed to etch"); + u3_assert( 0 ); + } + // TODO: better route management + _xmas_send_buf(sam_u, *lan_u, buf_y, siz_w); + _xmas_req_pact_sent(req_u, &nex_u->pac_u.pek_u.nam_u); + } + } +} + +static u3_pend_req* +_xmas_req_pact_init(u3_xmas* sam_u, u3_xmas_pict* pic_u, u3_lane* lan_u) +{ + u3_xmas_pact* pac_u = &pic_u->pac_u; + u3_xmas_name* nam_u = &pac_u->pag_u.nam_u; + u3_xmas_data* dat_u = &pac_u->pag_u.dat_u; + c3_o lin_o = dat_u->tot_w <= 4 ? c3y : c3n; + + u3_pend_req* req_u = u3a_calloc(1, sizeof(u3_pend_req)); + u3_gage* gag_u = _xmas_get_lane(sam_u, nam_u->her_d, lan_u); + + if ( gag_u == NULL ) { + gag_u = alloca(sizeof(u3_gage)); + _init_gage(gag_u); + // save and re-retrieve so we have persistent pointer + _xmas_put_lane(sam_u, nam_u->her_d, lan_u, gag_u); + gag_u = _xmas_get_lane(sam_u, nam_u->her_d, lan_u); + u3_assert( gag_u != NULL ); + } + + req_u->pic_u = c3_calloc(sizeof(u3_xmas_pict)); + req_u->pic_u->sam_u = sam_u; + req_u->pic_u->pac_u.hed_u.typ_y = PACT_PEEK; + req_u->pic_u->pac_u.hed_u.pro_y = XMAS_VER; + memcpy(&req_u->pic_u->pac_u.pek_u.nam_u, nam_u, sizeof(u3_xmas_name)); + req_u->pic_u->pac_u.pek_u.nam_u.aut_o = c3n; + req_u->pic_u->pac_u.pek_u.nam_u.nit_o = c3n; + + c3_w siz_w = 1 << (pac_u->pag_u.nam_u.boq_y - 3); + u3_assert( siz_w == 1024 ); // boq_y == 13 + req_u->gag_u = gag_u; + req_u->dat_y = c3_calloc(siz_w * dat_u->tot_w); + req_u->wat_u = c3_calloc(sizeof(u3_pact_stat) * dat_u->tot_w + 2 ); + req_u->tot_w = dat_u->tot_w; + bitset_init(&req_u->was_u, dat_u->tot_w); + + // TODO: handle restart + // u3_assert( nam_u->fra_w == 0 ); + + req_u->nex_w = (c3y == lin_o) ? 1 : 0; + req_u->len_w = (c3y == lin_o) ? 1 : 0; + uv_timer_init(u3L, &req_u->tim_u); + req_u->lef_w = 0; + req_u->old_w = 0; + req_u->ack_w = 0; + + memcpy(&(req_u->aum_u), &(dat_u->aum_u), sizeof(req_u->aum_u)); + + if ( c3y == lin_o ) { + u3_vec(c3_y[BLAKE3_OUT_LEN])* pof_u = vec_make(8); + { + blake_node* nod_u = blake_leaf_hash(dat_u->fra_y, dat_u->len_w, 0); + c3_y* lef_y = c3_calloc(BLAKE3_OUT_LEN); + make_chain_value(lef_y, nod_u); + c3_free(nod_u); + vec_append(pof_u, lef_y); + } + + for ( int i = 0; i < pac_u->pag_u.dat_u.aup_u.len_y; i++ ) { + c3_y* pof_y = c3_calloc(BLAKE3_OUT_LEN); + memcpy(pof_y, pac_u->pag_u.dat_u.aup_u.has_y[i], BLAKE3_OUT_LEN); + vec_append(pof_u, pof_y); + } + + req_u->bao_u = blake_bao_make(req_u->tot_w, pof_u); + // XX unchecked, failure here needs to cause a packet drop + // + blake_bao_verify(req_u->bao_u, dat_u->fra_y, dat_u->len_w, NULL); + memcpy(req_u->dat_y, dat_u->fra_y, dat_u->len_w); + } else { + c3_w len_w = dat_u->len_w / BLAKE3_OUT_LEN; + u3_vec(c3_y[BLAKE3_OUT_LEN])* pof_u = vec_make(len_w); + for ( int i = 0; i < len_w; i++ ) { + c3_y* pof_y = c3_calloc(BLAKE3_OUT_LEN); + memcpy(pof_y, dat_u->fra_y + (BLAKE3_OUT_LEN*i), BLAKE3_OUT_LEN); + vec_append(pof_u, pof_y); + } + req_u->bao_u = blake_bao_make(req_u->tot_w, pof_u); + } + vec_init(&req_u->mis_u, 8); + + // req_u = _xmas_put_request(sam_u, nam_u, req_u); + return req_u; +} + +/* _xmas_plan_mess(): construct and enqueue [%mess %page] ovum. +*/ +static u3_ovum* +_xmas_plan_mess(u3_xmas* sam_u, + u3_xmas_auth* aum_u, + u3_xmas_name* nam_u, + u3_lane* lan_u, + c3_w len_w, + c3_y* buf_y) +{ + u3_noun wir = u3nc(c3__xmas, u3_nul); + u3_noun aut, cad; + + switch ( aum_u->typ_e ) { + case AUTH_SIGN: { + aut = u3nc(c3y, u3i_bytes(64, aum_u->sig_y)); + } break; + + case AUTH_HMAC: { + aut = u3nc(c3n, u3i_bytes(32, aum_u->mac_y)); + } break; + + default: u3_assert(0); + } + + { + u3_noun pax = u3_xmas_encode_path(nam_u->pat_s, + (c3_y*)(nam_u->pat_c)); + u3_noun par = u3nc(u3i_chubs(2, nam_u->her_d), pax); + u3_noun lan = u3nc(u3_nul, u3_xmas_encode_lane(*lan_u)); + u3_noun dat = u3i_bytes(len_w, buf_y); + + cad = u3nt(c3__mess, lan, + u3nq(c3__page, par, aut, dat)); + } + return u3_auto_plan(&sam_u->car_u, + u3_ovum_init(0, c3__m, wir, cad)); +} + +static void +_xmas_hear_page(u3_xmas_pict* pic_u, u3_lane* lan_u) +{ +#ifdef XMAS_DEBUG + u3l_log("xmas hear %%page %u", pic_u->pac_u.pag_u.nam_u.fra_w); +#endif + u3_xmas* sam_u = pic_u->sam_u; + u3_xmas_pact* pac_u = &pic_u->pac_u; + u3_xmas_name *nam_u = &pac_u->pag_u.nam_u; + u3_xmas_data* dat_u = &pac_u->pag_u.dat_u; + + // XX move, more validation response before anything else (bloq size) + // + if ( 13 != nam_u->boq_y ) { + u3l_log("page: strange bloq size %u", nam_u->boq_y); + _xmas_free_pict(pic_u); + return; + } + if ( c3y == nam_u->nit_o ) { + switch ( dat_u->aum_u.typ_e ) { + case AUTH_SIGN: + case AUTH_HMAC: break; + + default: { + u3l_log("page: strange auth on first packet"); + _xmas_free_pict(pic_u); + return; + } + } + } + else if ( c3y == nam_u->aut_o ) { + u3l_log("page: strange auth packet"); + _xmas_free_pict(pic_u); + return; + } + + // XX this peer discovery is completely fake + // + { + u3_peer* per_u = _xmas_get_peer(sam_u, nam_u->her_d); + c3_o new_o = c3n; + if ( NULL == per_u ) { + new_o = c3y; + per_u = c3_calloc(sizeof(u3_peer)); + _init_peer(sam_u, per_u); + _meet_peer(sam_u, per_u, nam_u->her_d); + } + + c3_o dir_o = __(pac_u->hed_u.hop_y == 0); + if ( pac_u->hed_u.hop_y == 0 ) { + _hear_peer(sam_u, per_u, *lan_u, dir_o); + } else { + u3l_log("received forwarded page"); + } + if ( new_o == c3y ) { + //u3l_log("new lane is direct %c", c3y == dir_o ? 'y' : 'n'); + //_log_lane(&lan_u); + } + + _xmas_put_peer(sam_u, nam_u->her_d, per_u); + } + + // _pact_key pek_u = _xmas_pact_key(nam_u); + // u3m_p("page", pek_u.key); + + // XX if response to our request + // req_plan_init/req_plan_done + // if request in PIT, send response to all lanes + + _feat_key fek_u = _xmas_feat_key(nam_u); + u3_pend_req* req_u = _xmas_feat_git(sam_u, fek_u); + + // we're in the middle of this message + // + if ( req_u && (c3n == nam_u->nit_o) ) { + // push packet into feat + // if fails to validate, drop it + // + // XX cache if it "validates"? + // + req_u = _xmas_req_pact_done(sam_u, req_u, nam_u, dat_u, lan_u); + if ( req_u == NULL ) { + u3z(fek_u.key); + _xmas_free_pict(pic_u); + return; + } + + _xmas_req_pact_next(sam_u, req_u, lan_u); + + if ( req_u->len_w == req_u->tot_w ) { + // fprintf(stderr, "finished"); + // u3l_log("queue size %u", req_u->mis_u.len_w); + c3_d now_d = _get_now_micros(); + u3l_log("%u kilobytes took %f ms", req_u->tot_w, (now_d - sam_u->tim_d)/1000.0); + c3_w siz_w = (1 << (nam_u->boq_y - 3)); + + _xmas_plan_mess(sam_u, &req_u->aum_u, nam_u, + lan_u, (siz_w * req_u->tot_w), req_u->dat_y); + + // XX shouldn't delete request till success + _xmas_del_request(sam_u, nam_u); + } + } + + _pact_key pek_u = _xmas_pact_key(nam_u); + u3_weak hit = _xmas_pint_git(sam_u, pek_u); + + if ( u3_none != hit ) { + u3_noun tel = u3t(u3t(hit)); + u3_noun lis = u3t(tel); + c3_o our_o = u3h(tel); + + if ( c3y == our_o ) { + if ( c3y == nam_u->nit_o ) { + if ( 1 == dat_u->tot_w ) { + // XX should put in cache on success + // + _xmas_plan_mess(sam_u, &dat_u->aum_u, nam_u, + lan_u, dat_u->len_w, dat_u->fra_y); + } + else if ( !req_u ) { + // XX init request + req_u = _xmas_req_pact_init(sam_u, pic_u, lan_u); + if ( req_u == NULL ) { + u3z(fek_u.key); + u3z(pek_u.key); + _xmas_free_pict(pic_u); + return; + } + + _xmas_feat_put(sam_u, fek_u, req_u); + + _xmas_req_pact_next(sam_u, req_u, lan_u); + } + } + else if ( !req_u ) { + u3l_log("xmas: strange PIT entry for non init"); + // XX wat do? + } + } + + // XX reuse buffer, update hopcount, append lane + { + u3_noun lan = u3qdi_tap(lis); + c3_y* buf_y = c3_calloc(PACT_SIZE); + c3_w len_w = xmas_etch_pact(buf_y, &pic_u->pac_u); + + u3_assert( len_w ); + + _xmas_rout_bufs(sam_u, buf_y, len_w, lan); + } + + _xmas_pint_del(sam_u, pek_u); + } + + + u3z(fek_u.key); + u3z(pek_u.key); + _xmas_free_pict(pic_u); +} + +/* _xmas_plan_peek(): scry for a packet. +*/ +static void +_xmas_plan_peek(u3_xmas_pict* pic_u) +{ + u3_xmas* sam_u = pic_u->sam_u; + u3_pier* pir_u = sam_u->car_u.pir_u; + u3_xmas_name* nam_u = &pic_u->pac_u.pek_u.nam_u; + + u3_noun bem = u3nc(u3nt(u3i_chubs(2, nam_u->her_d), + u3_nul, + u3nc(c3__ud, 1)), + _name_to_scry(nam_u)); + u3_noun sam = u3nq(c3n, c3__beam, c3__mx, bem); + + u3_pier_peek(pir_u, u3_nul, sam, pic_u, _xmas_page_scry_cb); +} + +static void +_xmas_poke_news(u3_ovum* egg_u, u3_ovum_news new_e) +{ + u3_xmas_pict* pic_u = egg_u->ptr_v; + + if ( u3_ovum_done == new_e ) { + // XX update peer state + // XX initiate payload request if >1 fragment + u3l_log("xmas: poke success"); + } +} + +static void +_xmas_poke_bail(u3_ovum* egg_u, u3_noun lud) +{ + u3_xmas_pict* pic_u = egg_u->ptr_v; + // XX failure stuff here + u3l_log("xmas: poke failure"); +} + + +/* _xmas_plan_poke(): queue an ovum for a %poke a packet. +*/ +static void +_xmas_plan_poke(u3_xmas_pict* pic_u, u3_lane* lan_u) +{ + u3_xmas* sam_u = pic_u->sam_u; + u3_xmas_pact* pac_u = &pic_u->pac_u; + + u3_noun wir = u3nc(c3__xmas, u3_nul); + u3_noun cad; + { + u3_noun lan = u3_xmas_encode_lane(*lan_u); + u3i_slab sab_u; + u3i_slab_init(&sab_u, 3, PACT_SIZE); + + // XX should just preserve input buffer + xmas_etch_pact(sab_u.buf_y, pac_u); + + cad = u3nt(c3__heer, lan, u3i_slab_mint(&sab_u)); + } + + u3_ovum_peer nes_f; + u3_ovum_bail bal_f; + void* ptr_v; + + if ( 1 == pac_u->pok_u.dat_u.tot_w ) { + nes_f = bal_f = ptr_v = NULL; + _xmas_free_pict(pic_u); + } + else { + assert(pac_u->pok_u.dat_u.tot_w); + // XX check request state for *payload* (in-progress duplicate) + nes_f = _xmas_poke_news; + bal_f = _xmas_poke_bail; + ptr_v = pic_u; + } + + u3_auto_peer( + u3_auto_plan(&sam_u->car_u, + u3_ovum_init(0, c3__m, wir, cad)), + ptr_v, nes_f, bal_f); + + // XX defer lane management stuff to success callback (once vane works) + // + { + u3_peer* per_u = _xmas_get_peer(sam_u, pac_u->pok_u.pay_u.her_d); + c3_o new_o = c3n; + if ( NULL == per_u ) { + new_o = c3y; + per_u = c3_calloc(sizeof(u3_peer)); + _init_peer(sam_u, per_u); + _meet_peer(sam_u, per_u, pac_u->pok_u.pay_u.her_d); + } + + c3_o dir_o = __(pac_u->hed_u.hop_y == 0); + if ( pac_u->hed_u.hop_y == 0 ) { + new_o = c3y; + _hear_peer(sam_u, per_u, *lan_u, dir_o); + u3l_log("learnt lane"); + } else { + u3l_log("received forwarded poke"); + } + if ( new_o == c3y ) { + u3l_log("new lane is direct %c", c3y == dir_o ? 'y' : 'n'); + _log_lane(lan_u); + } + _xmas_put_peer(sam_u, pac_u->pok_u.pay_u.her_d, per_u); + } +} + +/* _xmas_hear_want(): handle a request (%peek or %poke) packet. +*/ +static void +_xmas_hear_want(u3_xmas_pict* pic_u, u3_lane* lan_u) +{ +#ifdef XMAS_DEBUG + u3l_log("xmas: hear %%%s", + (PACT_PEEK == pic_u->pac_u.hed_u.typ_y) ? "peek" : "poke"); +#endif + + u3_xmas* sam_u = pic_u->sam_u; + u3_xmas_pact* pac_u = &pic_u->pac_u; + u3_xmas_name* nam_u = &pac_u->pek_u.nam_u; // NB: works for both types + + c3_d* her_d = nam_u->her_d; + c3_o our_o = __( 0 == memcmp(her_d, sam_u->pir_u->who_d, sizeof(*her_d) * 2) ); + + // XX validate request before anything else (bloq size) + // - bloq = 13 + // - nit_o || !aut_o + + _pact_key pek_u = _xmas_pact_key(nam_u); + u3_weak hit = _xmas_cash_git(sam_u, pek_u); + + // u3m_p("want", pek_u.key); + + // if cached, give response + // + if ( u3_none != hit ) { + // XX send from cache + // XX respond synchronously, reusing pact/lane + // NB: hopcount should already be correct in cache +#if XMAS_DEBUG + u3l_log("xmas: hit cache mug=%x", u3r_mug(pek_u.key)); +#endif + c3_y* buf_y; + c3_w len_w = _xmas_respond(pic_u, &buf_y, hit); + _xmas_send_buf(sam_u, *lan_u, buf_y, len_w); + } + else { + hit = _xmas_pint_git(sam_u, pek_u); + + // if ours, track requester lane + // + if ( c3y == our_o ) { + _xmas_pint_add(sam_u, pek_u, c3n, u3_xmas_encode_lane(*lan_u), hit); + + // suppress duplicates + // + if ( u3_none == hit ) { +#if XMAS_DEBUG + u3l_log("xmas: plan mug=%x", u3r_mug(pek_u.key)); +#endif + if ( PACT_PEEK == pic_u->pac_u.hed_u.typ_y ) { + _xmas_plan_peek(pic_u); + } + else { + _xmas_plan_poke(pic_u, lan_u); + } + + u3z(pek_u.key); + return; // retain pic_u; + } + else { +#if XMAS_DEBUG + u3l_log("xmas: add to PIT mug=%x", u3r_mug(pek_u.key)); +#endif + } + } + // if we are relaying and have a route, track requester lane + // + // NB: duplicate requests *not* suppressed + // + else if ( c3y == sam_u->for_o ) { + // XX can't presume we have a route + // XX reuse buf and forward synchronously + // + u3_lane lin_u = _xmas_get_direct_lane(sam_u, her_d); + //_update_hopcount(&pac_u->hed_u); +#ifdef XMAS_DEBUG + u3l_log("xmas: forwarding mug=%x to=%u.%u.%u.%u:%u", + u3r_mug(pek_u.key), + (lin_u.pip_w >> 24) & 0xff, + (lin_u.pip_w >> 16) & 0xff, + (lin_u.pip_w >> 8) & 0xff, + (lin_u.pip_w >> 0) & 0xff, + lin_u.pip_w); +#endif + _xmas_send(pic_u, &lin_u); + + _xmas_pint_add(sam_u, pek_u, c3n, u3_xmas_encode_lane(*lan_u), hit); + } + } + + u3z(pek_u.key); + _xmas_free_pict(pic_u); +} + +static void +_xmas_hear(u3_xmas* sam_u, + u3_lane* lan_u, + c3_w len_w, + c3_y* hun_y) +{ + u3_xmas_pict* pic_u; + c3_w pre_w; + c3_y* cur_y = hun_y; + if ( HEAD_SIZE > len_w ) { + c3_free(hun_y); + return; + } + + pic_u = c3_calloc(sizeof(u3_xmas_pict)); + pic_u->sam_u = sam_u; + c3_w lin_w = xmas_sift_pact(&pic_u->pac_u, hun_y, len_w); + c3_free(hun_y); + if ( lin_w == 0 ) { + XMAS_LOG(SERIAL) + // XX revisit + // xmas_free_pact(&pic_u->pac_u); + c3_free(pic_u); + return; + } + + switch ( pic_u->pac_u.hed_u.typ_y ) { + case PACT_PAGE: { + _xmas_hear_page(pic_u, lan_u); + } break; + + default: { + _xmas_hear_want(pic_u, lan_u); + } break; + } +} + +static void +_xmas_recv_cb(uv_udp_t* wax_u, + ssize_t nrd_i, + const uv_buf_t * buf_u, + const struct sockaddr* adr_u, + unsigned flg_i) +{ + if ( 0 > nrd_i ) { + if ( u3C.wag_w & u3o_verbose ) { + u3l_log("xmas: recv: fail: %s", uv_strerror(nrd_i)); + } + c3_free(buf_u->base); + } + else if ( 0 == nrd_i ) { + c3_free(buf_u->base); + } + else if ( flg_i & UV_UDP_PARTIAL ) { + if ( u3C.wag_w & u3o_verbose ) { + u3l_log("xmas: recv: fail: message truncated"); + } + c3_free(buf_u->base); + } + else { + u3_xmas* sam_u = wax_u->data; + struct sockaddr_in* add_u = (struct sockaddr_in*)adr_u; + u3_lane lan_u; + + + lan_u.por_s = ntohs(add_u->sin_port); + // u3l_log("port: %s", lan_u.por_s); + lan_u.pip_w = ntohl(add_u->sin_addr.s_addr); + // u3l_log("IP: %x", lan_u.pip_w); + // NB: [nrd_i] will never exceed max length from _ames_alloc() + // + _xmas_hear(sam_u, &lan_u, (c3_w)nrd_i, (c3_y*)buf_u->base); + } +} + + + +static void +_xmas_io_talk(u3_auto* car_u) +{ + u3_xmas* sam_u = (u3_xmas*)car_u; + sam_u->dns_c = "urbit.org"; // TODO: receive turf + { + // XX remove [sev_l] + // + u3_noun wir = u3nt(c3__xmas, + u3dc("scot", c3__uv, sam_u->sev_l), + u3_nul); + u3_noun cad = u3nc(c3__born, u3_nul); + + u3_auto_plan(car_u, u3_ovum_init(0, c3__m, wir, cad)); + } + u3_noun who = u3i_chubs(2, sam_u->pir_u->who_d); + u3_noun rac = u3do("clan:title", u3k(who)); + c3_s por_s = sam_u->pir_u->por_s; + c3_i ret_i; + if ( c3__czar == rac ) { + c3_y num_y = (c3_y)sam_u->pir_u->who_d[0]; + c3_s zar_s = _ames_czar_port(num_y); + + if ( 0 == por_s ) { + por_s = zar_s; + } + else if ( por_s != zar_s ) { + u3l_log("ames: czar: overriding port %d with -p %d", zar_s, por_s); + u3l_log("ames: czar: WARNING: %d required for discoverability", zar_s); + } + } + + + // Bind and stuff. + { + struct sockaddr_in add_u; + c3_i add_i = sizeof(add_u); + + memset(&add_u, 0, sizeof(add_u)); + add_u.sin_family = AF_INET; + add_u.sin_addr.s_addr = _(u3_Host.ops_u.net) ? + htonl(INADDR_ANY) : + htonl(INADDR_LOOPBACK); + add_u.sin_port = htons(por_s); + + if ( (ret_i = uv_udp_bind(&sam_u->wax_u, + (const struct sockaddr*)&add_u, 0)) != 0 ) + { + u3l_log("xmas: bind: %s", uv_strerror(ret_i)); + + /*if ( (c3__czar == rac) && + (UV_EADDRINUSE == ret_i) ) + { + u3l_log(" ...perhaps you've got two copies of vere running?"); + }*/ + + // XX revise + // + u3_pier_bail(u3_king_stub()); + } + + uv_udp_getsockname(&sam_u->wax_u, (struct sockaddr *)&add_u, &add_i); + u3_assert(add_u.sin_port); + + sam_u->pir_u->por_s = ntohs(add_u.sin_port); + } + if ( c3y == u3_Host.ops_u.net ) { + u3l_log("xmas: live on %d", sam_u->pir_u->por_s); + } + else { + u3l_log("xmas: live on %d (localhost only)", sam_u->pir_u->por_s); + } + + uv_udp_recv_start(&sam_u->wax_u, _ames_alloc, _xmas_recv_cb); + + sam_u->car_u.liv_o = c3y; + //u3z(rac); u3z(who); +} + +static void +_xmas_ef_send(u3_xmas* sam_u, u3_noun las, u3_noun pac) +{ + las = _xmas_queue_czar(sam_u, las, u3k(pac)); + c3_w len_w = u3r_met(3, pac); + c3_y* buf_y = c3_calloc(len_w); + u3r_bytes(0, len_w, buf_y, pac); + sam_u->tim_d = _get_now_micros(); + + { + u3_xmas_pact pac_u; + u3_xmas_name* nam_u = &pac_u.pek_u.nam_u; // NB: works all types + + if ( 0 == xmas_sift_pact(&pac_u, buf_y, len_w) ) { + u3l_log("xmas: strange send"); + } + else { + _pact_key pek_u = _xmas_pact_key(nam_u); + u3_weak hit = _xmas_pint_git(sam_u, pek_u); + + switch ( pac_u.hed_u.typ_y ) { + case PACT_PAGE: { +#if XMAS_DEBUG + u3l_log("xmas: send %%page"); +#endif + + if ( u3_none != hit ) { + u3_noun tel = u3t(u3t(hit)); + u3_noun lis = u3t(tel); + c3_o our_o = u3h(tel); + + if ( c3y == our_o ) { + u3l_log("xmas: strange self request (gift)"); + } + + // unify (list lane) from effect with (set lane) in PIT + // + { + u3_noun lus = u3qdi_gas(lis, las);; + u3z(las); + las = u3kdi_tap(lus); + } + } + + _xmas_pint_del(sam_u, pek_u); + _xmas_cash_put(sam_u, pek_u, u3k(pac)); + } break; + + default: { +#if XMAS_DEBUG + u3l_log("xmas: send %%%s", + (PACT_PEEK == pac_u.hed_u.typ_y) ? "peek" : "poke"); +#endif + _xmas_pint_add(sam_u, pek_u, c3y, u3_none, hit); + } break; + } + + u3z(pek_u.key); + xmas_free_pact(&pac_u); + } + } + + c3_o suc_o = c3n; + _xmas_rout_bufs(sam_u, buf_y, len_w, las); + + c3_free(buf_y); + u3z(pac); +} + +static c3_o +_xmas_kick(u3_xmas* sam_u, u3_noun tag, u3_noun dat) +{ + c3_o ret_o; + + switch ( tag ) { + default: { + ret_o = c3n; + } break; + case c3__send: { + u3_noun las, pac; + if ( c3n == u3r_cell(dat, &las, &pac) ) { + ret_o = c3n; + } else { + _xmas_ef_send(sam_u, u3k(las), u3k(pac)); + ret_o = c3y; + } + } break; + } + + // technically losing tag is unncessary as it always should + // be a direct atom, but better to be strict + u3z(dat); u3z(tag); + return ret_o; +} + +static c3_o +_xmas_io_kick(u3_auto* car_u, u3_noun wir, u3_noun cad) +{ + u3_xmas* sam_u = (u3_xmas*)car_u; + + u3_noun tag, dat, i_wir; + c3_o ret_o; + + if ( (c3n == u3r_cell(wir, &i_wir, 0)) + || (c3__xmas != i_wir) + || (c3n == u3r_cell(cad, &tag, &dat)) ) + { + ret_o = c3n; + } + else { + ret_o = _xmas_kick(sam_u, u3k(tag), u3k(dat)); + } + + u3z(wir); u3z(cad); + return ret_o; +} + +static u3_noun +_xmas_io_info(u3_auto* car_u) +{ + + return u3_nul; +} + +static void +_xmas_io_slog(u3_auto* car_u) { + u3l_log("xmas is online"); +} + +static void +_xmas_exit_free(u3_noun kev) +{ + u3_post val = u3t(kev); + + if ( val ) { + u3a_free(u3a_into(val)); + } +} + +static void +_xmas_exit_cb(uv_handle_t* had_u) +{ + u3_xmas* sam_u = had_u->data; + + u3h_free(sam_u->cac_p); + u3h_free(sam_u->pit_p); + + u3h_walk(sam_u->her_p, _xmas_exit_free); + u3h_free(sam_u->her_p); + u3h_walk(sam_u->lan_p, _xmas_exit_free); + u3h_free(sam_u->lan_p); + // XX refactor _xmas_del_request(), walk + u3h_free(sam_u->req_p); + + c3_free(sam_u); +} + +static void +_xmas_io_exit(u3_auto* car_u) +{ + u3_xmas* sam_u = (u3_xmas*)car_u; + uv_close(&sam_u->had_u, _xmas_exit_cb); +} + +/* _xmas_io_init(): initialize ames I/O. +*/ +u3_auto* +u3_xmas_io_init(u3_pier* pir_u) +{ + u3_xmas* sam_u = c3_calloc(sizeof(*sam_u)); + sam_u->pir_u = pir_u; + + // these store pointers, not cap-able + sam_u->her_p = u3h_new(); + sam_u->req_p = u3h_new(); + sam_u->lan_p = u3h_new(); + + // XX config for max entries + // + sam_u->cac_p = u3h_new_cache(100000); + sam_u->pit_p = u3h_new_cache(10000); + + u3_assert( !uv_udp_init(u3L, &sam_u->wax_u) ); + sam_u->wax_u.data = sam_u; + + // Disable networking for fake ships + // + if ( c3y == sam_u->pir_u->fak_o ) { + u3_Host.ops_u.net = c3n; + } + + sam_u->for_o = c3n; + { + u3_noun her = u3i_chubs(2, pir_u->who_d); + for (int i = 0; i < 256; i++) { + sam_u->imp_u[i].pen = u3_nul; + sam_u->imp_u[i].sam_u = sam_u; + sam_u->imp_u[i].imp_y = i; + //sam_u.imp_u[i].tim = 0; + if ( u3_Host.ops_u.net == c3n ) { + sam_u->imp_u[i].pip_w = 0x7f000001; + } else { + sam_u->imp_u[i].pip_w = 0; + } + } + + if ( c3y == u3a_is_cat(her) && her < 256 ) { + u3l_log("xmas: forwarding enabled"); + sam_u->for_o = c3y; + } + u3z(her); + } + + + u3_auto* car_u = &sam_u->car_u; + car_u->nam_m = c3__xmas; + car_u->liv_o = c3y; + car_u->io.talk_f = _xmas_io_talk; + car_u->io.info_f = _xmas_io_info; + car_u->io.slog_f = _xmas_io_slog; + car_u->io.kick_f = _xmas_io_kick; + car_u->io.exit_f = _xmas_io_exit; + + + + /*{ + u3_noun now; + struct timeval tim_u; + gettimeofday(&tim_u, 0); + + now = u3_time_in_tv(&tim_u); + //sam_u->sev_l = u3r_mug(now); + u3z(now); + }*/ + + return car_u; +} diff --git a/pkg/vere/io/xmas/bitset.c b/pkg/vere/io/xmas/bitset.c new file mode 100644 index 0000000000..d58fd9ba4b --- /dev/null +++ b/pkg/vere/io/xmas/bitset.c @@ -0,0 +1,146 @@ +#include "bitset.h" +#include + +#include "vere.h" + + +#define u3_assert(x) \ + do { \ + if (!(x)) { \ + fflush(stderr); \ + fprintf(stderr, "\rAssertion '%s' " \ + "failed in %s:%d\r\n", \ + #x, __FILE__, __LINE__); \ + /*u3m_bail(c3__oops); */ \ + /*abort(); */ \ + } \ + } while(0) + + + +void bitset_init(u3_bitset* bit_u, c3_w len_w) +{ + bit_u->len_w = len_w; + bit_u->buf_y = c3_calloc(len_w >> 3); +} + +void +bitset_free(u3_bitset* bit_u) +{ + c3_free(bit_u->buf_y); +} + +static c3_y +_popcnt(c3_y num_y) +{ + return __builtin_popcount(num_y); +} + +static void +_log_bitset(u3_bitset* bit_u) +{ + c3_w cur_w = 0; + while( cur_w < bit_u->len_w ) { + if ( c3y == bitset_has(bit_u, cur_w) ) { + u3l_log("%u", cur_w); + } + cur_w++; + } +} + +c3_w +bitset_wyt(u3_bitset* bit_u) +{ + c3_w ret_w = 0; + c3_w len_w = (bit_u->len_w >> 3); + for(int i = 0; i < len_w; i++ ) { + ret_w += _popcnt(bit_u->buf_y[i]); + } + return ret_w; +} + +void bitset_put(u3_bitset* bit_u, c3_w mem_w) +{ + if (( mem_w > bit_u->len_w )) { + u3l_log("overrun %u, %u", mem_w, bit_u->len_w); + return; + } + c3_w idx_w = mem_w >> 3; + c3_w byt_y = bit_u->buf_y[idx_w]; + c3_y rem_y = mem_w & 0x7; + c3_y mas_y = (1 << rem_y); + bit_u->buf_y[idx_w] = byt_y | mas_y; +} + +c3_o +bitset_has(u3_bitset* bit_u, c3_w mem_w) { + if (( mem_w > bit_u->len_w )) { + u3l_log("overrun %u, %u", mem_w, bit_u->len_w); + return c3n; + } + + u3_assert( mem_w < bit_u->len_w ); + c3_w idx_w = mem_w >> 3; + c3_y rem_y = mem_w & 0x7; + return __( (bit_u->buf_y[idx_w] >> rem_y) & 0x1); +} + +void +bitset_del(u3_bitset* bit_u, c3_w mem_w) +{ + u3_assert( mem_w < bit_u->len_w ); + c3_w idx_w = mem_w >> 3; + c3_w byt_y = bit_u->buf_y[idx_w]; + c3_y rem_y = mem_w & 0x7; + c3_y mas_y = ~(1 << rem_y); + bit_u->buf_y[idx_w] &= mas_y; +} + + + + +#ifdef BITSET_TEST +c3_w main() +{ + u3_bitset bit_u; + bitset_init(&bit_u, 500); + + bitset_put(&bit_u, 5); + bitset_put(&bit_u, 50); + bitset_put(&bit_u, 100); + + c3_w wyt_w = bitset_wyt(&bit_u); + if ( 3 != wyt_w ) { + u3l_log("wyt failed have %u expect %u", wyt_w, 3); + exit(1); + } + + if ( c3y == bitset_has(&bit_u, 3) ) { + u3l_log("false positive for has_bitset"); + exit(1); + } + + if ( c3n == bitset_has(&bit_u, 50) ) { + u3l_log("false negative for has_bitset"); + exit(1); + } + + bitset_del(&bit_u, 50); + + if ( c3y == bitset_has(&bit_u, 50) ) { + u3l_log("false positive for has_bitset"); + exit(1); + } + + wyt_w = bitset_wyt(&bit_u); + + if ( 2 != wyt_w ) { + u3l_log("wyt failed have %u expect %u", wyt_w, 2); + exit(1); + } + return 0; +} + +#endif + + diff --git a/pkg/vere/io/xmas/bitset.h b/pkg/vere/io/xmas/bitset.h new file mode 100644 index 0000000000..eb76485f89 --- /dev/null +++ b/pkg/vere/io/xmas/bitset.h @@ -0,0 +1,23 @@ +#ifndef VERE_BITSET_H +#define VERE_BITSET_H + +#include "c3.h" + +typedef struct _u3_bitset { + c3_w len_w; + c3_y* buf_y; +} u3_bitset; + +void bitset_init(u3_bitset* bit_u, c3_w len_w); + +void bitset_free(u3_bitset* bit_u); + +c3_w bitset_wyt(u3_bitset* bit_u); + +void bitset_put(u3_bitset* bit_u, c3_w mem_w); + +c3_o bitset_has(u3_bitset* bit_u, c3_w mem_w); + +void bitset_del(u3_bitset* bit_u, c3_w mem_w); + +#endif \ No newline at end of file diff --git a/pkg/vere/io/xmas/pact.c b/pkg/vere/io/xmas/pact.c new file mode 100644 index 0000000000..f22a42a948 --- /dev/null +++ b/pkg/vere/io/xmas/pact.c @@ -0,0 +1,950 @@ +#include "xmas.h" +#include +// only need for tests, can remove +#include "vere.h" +#include "ivory.h" +#include "ur.h" +#define RED_TEXT "\033[0;31m" +#define DEF_TEXT "\033[0m" +// endif tests + +#define SIFT_VAR(dest, src, len) dest = 0; for(int i = 0; i < len; i++ ) { dest |= ((src + i) >> (8*i)); } +#define CHECK_BOUNDS(cur) if ( len_w < cur ) { u3l_log("xmas: failed parse (%u,%u) at line %i", len_w, cur, __LINE__); return 0; } +#define safe_dec(num) (num == 0 ? num : num - 1) +#define _xmas_met3_w(a_w) ((c3_bits_word(a_w) + 0x7) >> 3) + + +/* Logging functions +*/ + +static void +_log_head(u3_xmas_head* hed_u) +{ + u3l_log("-- HEADER --"); + u3l_log("next hop: %u", hed_u->nex_y); + u3l_log("protocol: %u", hed_u->pro_y); + u3l_log("packet type: %u", hed_u->typ_y); + u3l_log("mug: 0x%05x", (hed_u->mug_w & 0xFFFFF)); + u3l_log("hopcount: %u", hed_u->hop_y); + u3l_log(""); +} + + +static void +_log_buf(c3_y* buf_y, c3_w len_w) +{ + for( c3_w i_w = 0; i_w < len_w; i_w++ ) { + fprintf(stderr, "%02x", buf_y[i_w]); + } + fprintf(stderr, "\r\n"); +} + +static void +_log_name(u3_xmas_name* nam_u) +{ + // u3l_log("meta"); + // u3l_log("rank: %u", nam_u->met_u.ran_y); + // u3l_log("rift length: %u", nam_u->met_u.rif_y); + // u3l_log("nit: %u", nam_u->met_u.nit_y); + // u3l_log("tau: %u", nam_u->met_u.tau_y); + // u3l_log("frag num length: %u", nam_u->met_u.gaf_y); + + { + // u3_noun her = u3dc("scot", c3__p, u3i_chubs(2, nam_u->her_d)); + // c3_c* her_c = u3r_string(her); + // u3l_log("publisher: %s", her_c); + // c3_free(her_c); + // u3z(her); + } + + u3l_log("rift: %u", nam_u->rif_w); + u3l_log("bloq: %u", nam_u->boq_y); + u3l_log("init: %s", (c3y == nam_u->nit_o) ? "&" : "|"); + u3l_log("auth: %s", (c3y == nam_u->aut_o) ? "&" : "|"); + u3l_log("frag: %u", nam_u->fra_w); + u3l_log("path len: %u", nam_u->pat_s); + u3l_log("path: %s", nam_u->pat_c); +} + +static void +_log_data(u3_xmas_data* dat_u) +{ + u3l_log("total fragments: %u", dat_u->tot_w); + + switch ( dat_u->aum_u.typ_e ) { + case AUTH_NONE: { + if ( dat_u->aup_u.len_y ) { + u3l_log("strange no auth"); + } + else { + u3l_log("no auth"); + } + } break; + + case AUTH_NEXT: { + if ( 2 != dat_u->aup_u.len_y ) { + u3l_log("bad merkle traversal"); + } + else { + u3l_log("merkle traversal:"); + _log_buf(dat_u->aup_u.has_y[0], 32); + _log_buf(dat_u->aup_u.has_y[1], 32); + } + } break; + + case AUTH_SIGN: { + u3l_log("signature:"); + _log_buf(dat_u->aum_u.sig_y, 64); + } break; + + case AUTH_HMAC: { + u3l_log("hmac:"); + _log_buf(dat_u->aum_u.mac_y, 32); + } break; + } + + switch ( dat_u->aum_u.typ_e ) { + case AUTH_SIGN: + case AUTH_HMAC: { + if ( !dat_u->aup_u.len_y ) { + break; + } + + if ( 4 < dat_u->tot_w ) { + u3l_log("strange inline proof"); + } + else { + u3l_log("inline proof"); + } + + for ( int i = 0; i < dat_u->aup_u.len_y; i++ ) { + _log_buf(dat_u->aup_u.has_y[i], 32); + } + } break; + + default: break; + } + + u3l_log("frag len: %u", dat_u->len_w); +} + +static void +_log_peek_pact(u3_xmas_peek_pact* pac_u) +{ + _log_name(&pac_u->nam_u); +} + +static void +_log_page_pact(u3_xmas_page_pact *pac_u) +{ + _log_name(&pac_u->nam_u); + _log_data(&pac_u->dat_u); +} + +static void +_log_poke_pact(u3_xmas_poke_pact *pac_u) +{ + _log_name(&pac_u->nam_u); + _log_name(&pac_u->pay_u); + _log_data(&pac_u->dat_u); +} + +void +_log_pact(u3_xmas_pact* pac_u) +{ + switch ( pac_u->hed_u.typ_y ) { + case PACT_PEEK: { + _log_peek_pact(&pac_u->pek_u); + } break; + + case PACT_PAGE: { + _log_page_pact(&pac_u->pag_u); + } break; + + case PACT_POKE: { + _log_poke_pact(&pac_u->pok_u); + } break; + + default: { + _log_poke_pact(&pac_u->pok_u); + break; + } + } +} + +/* Helper utilities +*/ +static void +_update_hopcount(u3_xmas_head* hed_u) +{ + hed_u->hop_y = c3_max(hed_u->hop_y+1, 7); +} + +static c3_y +_xmas_rank(c3_d who_d[2]) +{ + if ( who_d[1] ) { + return 3; + } + else if ( who_d[0] >> 32 ) { + return 2; + } + else if ( who_d[0] >> 16 ) { + return 1; + } + else { + return 0; + } +} + +/* lifecycle +*/ + +/* xmas_free_pact(): free contents of packet. +* Does *not* free pac_u itself +*/ +void xmas_free_pact(u3_xmas_pact* pac_u) +{ + switch ( pac_u->hed_u.typ_y ) { + default: { + break; + }; + case PACT_PEEK: { + break; + }; + case PACT_PAGE: { + c3_free(pac_u->pag_u.dat_u.fra_y); + break; + }; + case PACT_POKE: { + c3_free(pac_u->pok_u.dat_u.fra_y); + break; + }; + } +} + +/* deserialisation +*/ + +static void +_ames_etch_word(c3_y buf_y[4], c3_w wod_w) +{ + buf_y[0] = wod_w & 0xff; + buf_y[1] = (wod_w >> 8) & 0xff; + buf_y[2] = (wod_w >> 16) & 0xff; + buf_y[3] = (wod_w >> 24) & 0xff; +} + + + +/* _ames_chub_bytes(): c3_d to c3_y[8] +** XX factor out, deduplicate with other conversions +*/ +static inline void +_ames_bytes_chub(c3_y byt_y[8], c3_d num_d) +{ + byt_y[0] = num_d & 0xff; + byt_y[1] = (num_d >> 8) & 0xff; + byt_y[2] = (num_d >> 16) & 0xff; + byt_y[3] = (num_d >> 24) & 0xff; + byt_y[4] = (num_d >> 32) & 0xff; + byt_y[5] = (num_d >> 40) & 0xff; + byt_y[6] = (num_d >> 48) & 0xff; + byt_y[7] = (num_d >> 56) & 0xff; +} + +static inline void +_ames_ship_of_chubs(c3_d sip_d[2], c3_y len_y, c3_y* buf_y) +{ + c3_y sip_y[16] = {0}; + + _ames_bytes_chub(sip_y, sip_d[0]); + _ames_bytes_chub(sip_y + 8, sip_d[1]); + + memcpy(buf_y, sip_y, c3_min(16, len_y)); +} + +static inline c3_d +_ames_chub_bytes(c3_y byt_y[8]) +{ + return (c3_d)byt_y[0] + | (c3_d)byt_y[1] << 8 + | (c3_d)byt_y[2] << 16 + | (c3_d)byt_y[3] << 24 + | (c3_d)byt_y[4] << 32 + | (c3_d)byt_y[5] << 40 + | (c3_d)byt_y[6] << 48 + | (c3_d)byt_y[7] << 56; +} + +static inline c3_w +_ames_sift_word(c3_y buf_y[4]) +{ + return (buf_y[3] << 24 | buf_y[2] << 16 | buf_y[1] << 8 | buf_y[0]); +} + + +static inline void +_ames_ship_to_chubs(c3_d sip_d[2], c3_y len_y, c3_y* buf_y) +{ + c3_y sip_y[16] = {0}; + memcpy(sip_y, buf_y, c3_min(16, len_y)); + + sip_d[0] = _ames_chub_bytes(sip_y); + sip_d[1] = _ames_chub_bytes(sip_y + 8); +} + +static c3_o +_xmas_sift_head(c3_y buf_y[8], u3_xmas_head* hed_u) +{ + if ( memcmp(buf_y + 4, &XMAS_COOKIE, XMAS_COOKIE_LEN) ) { + return c3n; + + } + c3_w hed_w = _ames_sift_word(buf_y); + + hed_u->nex_y = (hed_w >> 2) & 0x3; + hed_u->pro_y = (hed_w >> 4) & 0x7; + hed_u->typ_y = (hed_w >> 7) & 0x3; + hed_u->hop_y = (hed_w >> 9) & 0x7; + hed_u->mug_w = (hed_w >> 12) & 0xFFFFF; + + assert( 1 == hed_u->pro_y ); + + return c3y; + + /*if(c3o((hed_u->typ_y == PACT_PEEK), (hed_u->typ_y == PACT_POKE))) { + hed_u->ran_y = (hed_w >> 30) & 0x3; + }*/ +} + +static c3_w +_xmas_sift_name(u3_xmas_name* nam_u, c3_y* buf_y, c3_w len_w) +{ +#ifdef XMAS_DEBUG + //u3l_log("xmas: sifting name %i", len_w); +#endif + + c3_w cur_w = 0; + u3_xmas_name_meta met_u; + + CHECK_BOUNDS(cur_w + 1); + c3_y met_y = buf_y[cur_w]; + met_u.ran_y = (met_y >> 0) & 0x3; + met_u.rif_y = (met_y >> 2) & 0x3; + met_u.nit_y = (met_y >> 4) & 0x1; + met_u.tau_y = (met_y >> 5) & 0x1; + met_u.gaf_y = (met_y >> 6) & 0x3; + cur_w += 1; + + c3_y her_y = 2 << met_u.ran_y; + CHECK_BOUNDS(cur_w + her_y) + _ames_ship_to_chubs(nam_u->her_d, her_y, buf_y + cur_w); + cur_w += her_y; + + c3_y rif_y = met_u.rif_y + 1; + nam_u->rif_w = 0; + CHECK_BOUNDS(cur_w + rif_y) + for( int i = 0; i < rif_y; i++ ) { + nam_u->rif_w |= (buf_y[cur_w] << (8*i)); + cur_w++; + } + + CHECK_BOUNDS(cur_w + 1); + nam_u->boq_y = buf_y[cur_w]; + cur_w++; + + if ( met_u.nit_y ) { + assert( !met_u.tau_y ); + // XX init packet + nam_u->fra_w = 0; + } + else { + c3_y fag_y = met_u.gaf_y + 1; + CHECK_BOUNDS(cur_w + fag_y); + for ( int i = 0; i < fag_y; i++ ) { + nam_u->fra_w |= (buf_y[cur_w] << (8*i)); + cur_w++; + } + } + + nam_u->nit_o = ( met_u.nit_y ) ? c3y : c3n; + // XX ?:(=(1 tau.c) %auth %data) + nam_u->aut_o = ( met_u.tau_y ) ? c3y : c3n; + + CHECK_BOUNDS(cur_w + 2) + nam_u->pat_s = buf_y[cur_w] + | (buf_y[cur_w + 1] << 8); + cur_w += 2; + + nam_u->pat_c = c3_calloc(nam_u->pat_s + 1); // unix string for ease of manipulation + CHECK_BOUNDS(cur_w + nam_u->pat_s); + memcpy(nam_u->pat_c, buf_y + cur_w, nam_u->pat_s); + nam_u->pat_c[nam_u->pat_s] = 0; + cur_w += nam_u->pat_s; + + return cur_w; +} + +static c3_w +_xmas_sift_data(u3_xmas_data* dat_u, c3_y* buf_y, c3_w len_w) +{ +#ifdef XMAS_DEBUG + //u3l_log("xmas: sifting data %i", len_w); +#endif + + c3_w cur_w = 0; + u3_xmas_data_meta met_u; + + CHECK_BOUNDS(cur_w + 1); + c3_y met_y = buf_y[cur_w]; + met_u.bot_y = (met_y >> 0) & 0x3; + met_u.aul_y = (met_y >> 2) & 0x3; + met_u.aur_y = (met_y >> 4) & 0x3; + met_u.men_y = (met_y >> 6) & 0x3; + cur_w += 1; + + c3_y tot_y = met_u.bot_y + 1; + CHECK_BOUNDS(cur_w + tot_y); + dat_u->tot_w = 0; + for( int i = 0; i < tot_y; i++ ) { + dat_u->tot_w |= (buf_y[cur_w] << (8*i)); + cur_w++; + } + + c3_y aum_y = ( 2 == met_u.aul_y ) ? 64 : + ( 3 == met_u.aul_y ) ? 32 : 0; + CHECK_BOUNDS(cur_w + aum_y); + memcpy(dat_u->aum_u.sig_y, buf_y + cur_w, aum_y); + cur_w += aum_y; + + dat_u->aum_u.typ_e = met_u.aul_y; // XX + + assert( 3 > met_u.aur_y ); + + CHECK_BOUNDS(cur_w + (met_u.aur_y * 32)); + dat_u->aup_u.len_y = met_u.aur_y; + for( int i = 0; i < met_u.aur_y; i++ ) { + memcpy(dat_u->aup_u.has_y[i], buf_y + cur_w, 32); + cur_w += 32; + } + + c3_y nel_y = met_u.men_y; + + if ( 3 == nel_y ) { + CHECK_BOUNDS(cur_w + 1); + nel_y = buf_y[cur_w]; + cur_w++; + } + + CHECK_BOUNDS(cur_w + nel_y); + dat_u->len_w = 0; + for ( int i = 0; i < nel_y; i++ ) { + dat_u->len_w |= (buf_y[cur_w] << (8*i)); + cur_w++; + } + + CHECK_BOUNDS(cur_w + dat_u->len_w); + dat_u->fra_y = c3_calloc(dat_u->len_w); + memcpy(dat_u->fra_y, buf_y + cur_w, dat_u->len_w); + cur_w += dat_u->len_w; + + return cur_w; +} + +static c3_w +_xmas_sift_hop_long(u3_xmas_hop_once* hop_u, c3_y* buf_y, c3_w len_w) +{ + c3_w cur_w = 0; + CHECK_BOUNDS(cur_w + 1); + hop_u->len_w = buf_y[cur_w]; + cur_w++; + CHECK_BOUNDS(cur_w + hop_u->len_w); + hop_u->dat_y = c3_calloc(hop_u->len_w); + memcpy(hop_u->dat_y, buf_y + cur_w, hop_u->len_w); + + return cur_w; +} + + +static c3_w +_xmas_sift_page_pact(u3_xmas_pact* pat_u, c3_y nex_y, c3_y* buf_y, c3_w len_w) +{ + u3_xmas_page_pact* pac_u = &pat_u->pag_u; + c3_w cur_w = 0, nex_w; + + if ( !(nex_w = _xmas_sift_name(&pac_u->nam_u, buf_y + cur_w, len_w)) ) { + return 0; + } + cur_w += nex_w; + + if ( !(nex_w = _xmas_sift_data(&pac_u->dat_u, buf_y + cur_w, len_w)) ) { + return 0; + } + cur_w += nex_w; + + switch ( nex_y ) { + default: { + return 0; + } + case HOP_NONE: break; + case HOP_SHORT: { + CHECK_BOUNDS(cur_w + 6); + memcpy(pac_u->sot_u, buf_y + cur_w, 6); + cur_w += 6; + } break; + case HOP_LONG: { + c3_w hop_w = _xmas_sift_hop_long(&pac_u->one_u, buf_y + cur_w, len_w - cur_w); + if( hop_w == 0 ) { + return 0; + } + cur_w += hop_w; + } break; + case HOP_MANY: { + CHECK_BOUNDS(cur_w + 1); + pac_u->man_u.len_w = buf_y[cur_w]; + cur_w++; + + pac_u->man_u.dat_y = c3_calloc(sizeof(u3_xmas_hop_once) * pac_u->man_u.len_w); + + for( int i = 0; i < pac_u->man_u.len_w; i++ ) { + c3_w hop_w = _xmas_sift_hop_long(&pac_u->man_u.dat_y[i], buf_y + cur_w ,len_w - cur_w); + if ( hop_w == 0 ) { + return 0; + } + cur_w += hop_w; + } + } + } + + return cur_w; +} + + +static c3_w +_xmas_sift_peek_pact(u3_xmas_peek_pact* pac_u, c3_y* buf_y, c3_w len_w) +{ + c3_w siz_w = _xmas_sift_name(&pac_u->nam_u, buf_y, len_w); + if ( siz_w < len_w ) { + u3l_log("xmas: failed to consume entire packet"); + _log_buf(buf_y + siz_w, len_w - siz_w); + return 0; + } + + return siz_w; +} + +static c3_w +_xmas_sift_poke_pact(u3_xmas_poke_pact* pac_u, c3_y* buf_y, c3_w len_w) +{ + c3_w cur_w = 0, nex_w; + // ack path + if ( !(nex_w = _xmas_sift_name(&pac_u->nam_u, buf_y + cur_w, len_w)) ) { + return 0; + } + cur_w += nex_w; + + // payload path + if ( !(nex_w = _xmas_sift_name(&pac_u->pay_u, buf_y + cur_w, len_w)) ) { + return 0; + } + cur_w += nex_w; + + // payload + if ( !(nex_w = _xmas_sift_data(&pac_u->dat_u, buf_y + cur_w, len_w)) ) { + return 0; + } + cur_w += nex_w; + + return cur_w; +} + +c3_w +xmas_sift_pact(u3_xmas_pact* pac_u, c3_y* buf_y, c3_w len_w) +{ + c3_w res_w = 0; + + if ( len_w < 8 ) { + u3l_log("xmas: attempted to parse overly short packet of size %u", len_w); + } + + _xmas_sift_head(buf_y, &pac_u->hed_u); + buf_y += 8; + len_w -= 8; + + switch ( pac_u->hed_u.typ_y ) { + case PACT_PEEK: { + res_w = _xmas_sift_peek_pact(&pac_u->pek_u, buf_y, len_w); + } break; + case PACT_PAGE: { + res_w = _xmas_sift_page_pact(pac_u, pac_u->hed_u.nex_y, buf_y, len_w); + } break; + case PACT_POKE: { + res_w = _xmas_sift_poke_pact(&pac_u->pok_u, buf_y, len_w); + } break; + default: { + u3l_log("xmas: received unknown packet type"); + _log_buf(buf_y, len_w); + return 0; + } + } + + { + c3_w mug_w = u3r_mug_bytes(buf_y, res_w); + mug_w &= 0xFFFFF; + + if ( mug_w != pac_u->hed_u.mug_w ) { + u3l_log("xmas: failed mug"); + return 0; + } + } + + //u3_assert(res_w <= len_w ); + return res_w + 8; +} + +/* serialisation +*/ +static void +_xmas_etch_head(u3_xmas_head* hed_u, c3_y buf_y[8]) +{ + if ( 1 != hed_u->pro_y ) { + u3l_log("etching bad head"); + } + + // c3_o req_o = c3o((hed_u->typ_y == PACT_PEEK), (hed_u->typ_y == PACT_POKE)); + // c3_y siz_y = req_o ? 5 : 7; + c3_w hed_w = (hed_u->nex_y & 0x3) << 2 + ^ (hed_u->pro_y & 0x7) << 4 // XX constant, 1 + ^ (hed_u->typ_y & 0x3) << 7 + ^ (hed_u->hop_y & 0x7) << 9 + ^ (hed_u->mug_w & 0xFFFFF) << 12; + // XX: we don't expand hopcount if no request. Correct? + // + /*if ( c3y == req_o ) { + hed_w = hed_w ^ ((hed_u->ran_y & 0x3) << 30); + }*/ + + _ames_etch_word(buf_y, hed_w); + memcpy(buf_y + 4, XMAS_COOKIE, XMAS_COOKIE_LEN); +} + +static c3_w +_xmas_etch_name(c3_y* buf_y, u3_xmas_name* nam_u) +{ +#ifdef XMAS_DEBUG + +#endif + c3_w cur_w = 0; + u3_xmas_name_meta met_u; + + met_u.ran_y = _xmas_rank(nam_u->her_d); + met_u.rif_y = safe_dec(_xmas_met3_w(nam_u->rif_w)); + + if ( c3y == nam_u->nit_o ) { + assert( c3n == nam_u->aut_o ); // XX + met_u.nit_y = 1; + met_u.tau_y = 0; + met_u.gaf_y = 0; + } + else { + met_u.nit_y = 0; + met_u.tau_y = (c3y == nam_u->aut_o) ? 1 : 0; + met_u.gaf_y = safe_dec(_xmas_met3_w(nam_u->fra_w)); + } + + c3_y met_y = (met_u.ran_y & 0x3) << 0 + ^ (met_u.rif_y & 0x3) << 2 + ^ (met_u.nit_y & 0x1) << 4 + ^ (met_u.tau_y & 0x1) << 5 + ^ (met_u.gaf_y & 0x3) << 6; + + buf_y[cur_w] = met_y; + + //ship + cur_w++; + c3_y her_y = 2 << met_u.ran_y; // XX confirm + _ames_ship_of_chubs(nam_u->her_d, her_y, buf_y + cur_w); + cur_w += her_y; + + // rift + c3_y rif_y = met_u.rif_y + 1; + for ( int i = 0; i < rif_y; i++) { + buf_y[cur_w] = (nam_u->rif_w >> (8*i)) & 0xff; + cur_w++; + } + + buf_y[cur_w] = nam_u->boq_y; + cur_w++; + + c3_y fra_y = (c3y == nam_u->nit_o) ? 0 : met_u.gaf_y + 1; + for( int i = 0; i < fra_y; i++ ) { + buf_y[cur_w] = (nam_u->fra_w >> (8*i)) & 0xff; + cur_w++; + } + + // path length + c3_y pat_y = 2; + for ( int i = 0; i < pat_y; i++ ) { + buf_y[cur_w] = (nam_u->pat_s >> (8*i)) & 0xff; + cur_w++; + } + + // path + memcpy(buf_y + cur_w, nam_u->pat_c, nam_u->pat_s); + cur_w += nam_u->pat_s; + + return cur_w; +} + +static c3_w +_xmas_etch_data(c3_y* buf_y, u3_xmas_data* dat_u) +{ +#ifdef XMAS_DEBUG + +#endif + c3_w cur_w = 0; + u3_xmas_data_meta met_u; + + met_u.bot_y = safe_dec(_xmas_met3_w(dat_u->tot_w)); + + // XX + met_u.aul_y = dat_u->aum_u.typ_e; + met_u.aur_y = dat_u->aup_u.len_y; + + c3_y nel_y = _xmas_met3_w(dat_u->len_w); + met_u.men_y = (3 >= nel_y) ? nel_y : 3; + + c3_y met_y = (met_u.bot_y & 0x3) << 0 + ^ (met_u.aul_y & 0x3) << 2 + ^ (met_u.aur_y & 0x3) << 4 + ^ (met_u.men_y & 0x3) << 6; + buf_y[cur_w] = met_y; + cur_w++; + + c3_y tot_y = met_u.bot_y + 1; + for (int i = 0; i < tot_y; i++ ) { + buf_y[cur_w] = (dat_u->tot_w >> (8 * i)) & 0xFF; + cur_w++; + } + + switch ( dat_u->aum_u.typ_e ) { + case AUTH_SIGN: { + memcpy(buf_y + cur_w, dat_u->aum_u.sig_y, 64); + cur_w += 64; + } break; + + case AUTH_HMAC: { + memcpy(buf_y + cur_w, dat_u->aum_u.mac_y, 32); + cur_w += 32; + } break; + + default: break; + } + + for ( int i = 0; i < dat_u->aup_u.len_y; i++ ) { + memcpy(buf_y + cur_w, dat_u->aup_u.has_y[i], 32); + cur_w += 32; + } + + if ( 3 == met_u.men_y ) { + buf_y[cur_w] = nel_y; + cur_w++; + } + + memcpy(buf_y + cur_w, (c3_y*)&dat_u->len_w, nel_y); + cur_w += nel_y; + + memcpy(buf_y + cur_w, dat_u->fra_y, dat_u->len_w); + cur_w += dat_u->len_w; + + return cur_w; +} + +static c3_w +_xmas_etch_page_pact(c3_y* buf_y, u3_xmas_page_pact* pac_u, u3_xmas_head* hed_u) +{ + c3_w cur_w = 0, nex_w; + + if ( !(nex_w = _xmas_etch_name(buf_y + cur_w, &pac_u->nam_u)) ) { + return 0; + } + cur_w += nex_w; + + if ( !(nex_w = _xmas_etch_data(buf_y + cur_w, &pac_u->dat_u)) ) { + return 0; + } + cur_w += nex_w; + + // XX hops + + return cur_w; +} + +static c3_w +_xmas_etch_poke_pact(c3_y* buf_y, u3_xmas_poke_pact* pac_u, u3_xmas_head* hed_u) +{ + c3_w cur_w = 0, nex_w; + + if ( !(nex_w = _xmas_etch_name(buf_y + cur_w, &pac_u->nam_u)) ) { + return 0; + } + cur_w += nex_w; + + if ( !(nex_w = _xmas_etch_name(buf_y + cur_w, &pac_u->pay_u)) ) { + return 0; + } + cur_w += nex_w; + + if ( !(nex_w = _xmas_etch_data(buf_y + cur_w, &pac_u->dat_u)) ) { + return 0; + } + cur_w += nex_w; + + return cur_w; +} + + + +/* sizing +*/ +static c3_w +_xmas_size_name(u3_xmas_name* nam_u) +{ + c3_w siz_w = 1; + u3_xmas_name_meta met_u; + + met_u.ran_y = _xmas_rank(nam_u->her_d); + met_u.rif_y = safe_dec(_xmas_met3_w(nam_u->rif_w)); + + siz_w += 2 << met_u.ran_y; + siz_w += met_u.rif_y + 1; + siz_w++; // bloq + + if (c3n == nam_u->nit_o ) { + met_u.gaf_y = safe_dec(_xmas_met3_w(nam_u->fra_w)); + siz_w += met_u.gaf_y + 1; + } + + siz_w += 2; // path-length + siz_w += nam_u->pat_s; + + return siz_w; +} + +static c3_w +_xmas_size_data(u3_xmas_data* dat_u) +{ + c3_w siz_w = 1; + u3_xmas_data_meta met_u; + + met_u.bot_y = safe_dec(_xmas_met3_w(dat_u->tot_w)); + + siz_w += met_u.bot_y + 1; + + switch ( dat_u->aum_u.typ_e ) { + case AUTH_SIGN: { + siz_w += 64; + } break; + + case AUTH_HMAC: { + siz_w += 32; + } break; + + default: break; + } + + siz_w += 32 * dat_u->aup_u.len_y; + + c3_y nel_y = _xmas_met3_w(dat_u->len_w); + met_u.men_y = (3 >= nel_y) ? nel_y : 3; + + if ( 3 == met_u.men_y ) { + siz_w++; + } + + siz_w += nel_y; + siz_w += dat_u->len_w; + + return siz_w; +} + +static c3_w +_xmas_size_pact(u3_xmas_pact* pac_u) +{ + c3_w siz_w = 8; // header + cookie; + + switch ( pac_u->hed_u.typ_y ) { + case PACT_PEEK: { + siz_w += _xmas_size_name(&pac_u->pek_u.nam_u); + } break; + + case PACT_PAGE: { + siz_w += _xmas_size_name(&pac_u->pag_u.nam_u); + siz_w += _xmas_size_data(&pac_u->pag_u.dat_u); + // XX hops + } break; + + case PACT_POKE: { + siz_w += _xmas_size_name(&pac_u->pok_u.nam_u); + siz_w += _xmas_size_name(&pac_u->pok_u.pay_u); + siz_w += _xmas_size_data(&pac_u->pok_u.dat_u); + } break; + + default: { + u3l_log("bad pact type %u", pac_u->hed_u.typ_y);//u3m_bail(c3__bail); + return 0; + } + } + + return siz_w; +} + +c3_w +xmas_etch_pact(c3_y* buf_y, u3_xmas_pact* pac_u) +{ + c3_w siz_w = _xmas_size_pact(pac_u); + if ( siz_w > PACT_SIZE ) { + fprintf(stderr, "etch: would overflow %u\r\n", siz_w); + return 0; + } + + u3_xmas_head* hed_u = &pac_u->hed_u; + + c3_w nex_w, cur_w = 8; // space for header + cookie + + switch ( pac_u->hed_u.typ_y ) { + case PACT_POKE: { + if ( !(nex_w = _xmas_etch_poke_pact(buf_y + cur_w, &pac_u->pok_u, hed_u)) ) { + return 0; + } + } break; + + case PACT_PEEK: { + if ( !(nex_w = _xmas_etch_name(buf_y + cur_w, &pac_u->pek_u.nam_u)) ) { + return 0; + } + } break; + + case PACT_PAGE: { + if ( !(nex_w = _xmas_etch_page_pact(buf_y + cur_w, &pac_u->pag_u, hed_u)) ) { + return 0; + } + } break; + + default: { + u3l_log("bad pact type %u", pac_u->hed_u.typ_y);//u3m_bail(c3__bail); + return 0; + } + } + + hed_u->mug_w = u3r_mug_bytes(buf_y + cur_w, nex_w); + hed_u->mug_w &= 0xFFFFF; + _xmas_etch_head(hed_u, buf_y); + + cur_w += nex_w; + + assert( siz_w == cur_w ); + + return cur_w; +} diff --git a/pkg/vere/io/xmas/xmas.h b/pkg/vere/io/xmas/xmas.h new file mode 100644 index 0000000000..45ffe26bfc --- /dev/null +++ b/pkg/vere/io/xmas/xmas.h @@ -0,0 +1,163 @@ +#ifndef VERE_XMAS_H +#define VERE_XMAS_H + +#include "c3.h" + +#define XMAS_VER 1 +#define FINE_PAGE 4096 // packets per page +#define FINE_FRAG 1024 // bytes per fragment packet +#define FINE_PATH_MAX 384 // longest allowed scry path +#define HEAD_SIZE 4 // header size in bytes +#define PACT_SIZE 1472 + +#define HOP_NONE 0b0 +#define HOP_SHORT 0b1 +#define HOP_LONG 0b10 +#define HOP_MANY 0b11 + +#define XMAS_COOKIE_LEN 4 +static c3_y XMAS_COOKIE[4] = { 0x5e, 0x1d, 0xad, 0x51 }; + + +typedef enum _u3_xmas_ptag { + PACT_RESV = 0, + PACT_PAGE = 1, + PACT_PEEK = 2, + PACT_POKE = 3, +} u3_xmas_ptag; + +typedef enum _u3_xmas_rout_tag { + ROUT_GALAXY = 0, + ROUT_OTHER = 1 +} u3_xmas_rout_tag; + +typedef enum _u3_xmas_nexh { + NEXH_NONE = 0, + NEXH_SBYT = 1, + NEXH_ONLY = 2, + NEXH_MANY = 3 +} u3_xmas_nexh; + +typedef struct _u3_xmas_name_meta { + c3_y ran_y; // rank (2 bits) + c3_y rif_y; // rift-len (2 bits) + c3_y nit_y; // initial overlay (1 bit) + c3_y tau_y; // %data (0) or %auth (1), 0 if !nit_o (1 bit) + c3_y gaf_y; // fragment number length (2bit) +} u3_xmas_name_meta; + +typedef struct _u3_xmas_name { + // u3_xmas_name_meta met_u; + c3_d her_d[2]; + c3_w rif_w; + c3_y boq_y; + c3_o nit_o; + c3_o aut_o; + c3_w fra_w; + c3_s pat_s; + c3_c* pat_c; +} u3_xmas_name; + +typedef struct _u3_xmas_data_meta { + c3_y bot_y; // total-fragments len (2 bits) + c3_y aul_y; // auth-left (message) type (2 bits) + c3_y aur_y; // auth-right (packet) type (2 bits) + c3_y men_y; // fragment length/type (2 bits) +} u3_xmas_data_meta; + +typedef enum { + AUTH_NONE = 0, + AUTH_NEXT = 1, // %1, must be two hash + AUTH_SIGN = 2, // %0, hashes are optional depending on num frag + AUTH_HMAC = 3 +} u3_xmas_auth_type; + +typedef struct _u3_xmas_auth { + u3_xmas_auth_type typ_e; // none, traversal (none), sig, or hmac + union { // + c3_y sig_y[64]; // signature + c3_y mac_y[32]; // hmac + }; +} u3_xmas_auth; + +typedef struct _u3_xmas_data { + // u3_xmas_data_meta met_u; + c3_w tot_w; // total fragments + u3_xmas_auth aum_u; + struct { + c3_y len_y; // number of hashes (0, 1, or 2) + c3_y has_y[2][32]; // hashes + } aup_u; + c3_w len_w; // fragment length + c3_y* fra_y; // fragment +} u3_xmas_data; + + +typedef struct _u3_xmas_head { + u3_xmas_nexh nex_y; // next-hop + c3_y pro_y; // protocol version + u3_xmas_ptag typ_y; // packet type + c3_y hop_y; // hopcount + c3_w mug_w; // truncated mug checksum +} u3_xmas_head; + +// +// +$ cache +// [%rout lanes=(list lanes)] +// [%pending pacs=(list pact)] + + +typedef struct _u3_xmas_peek_pact { + u3_xmas_name nam_u; +} u3_xmas_peek_pact; + +typedef struct _u3_xmas_hop { + c3_w len_w; + c3_y* dat_y; +} u3_xmas_hop_once; + +typedef struct _u3_xmas_hop_more { + c3_w len_w; + u3_xmas_hop_once* dat_y; +} u3_xmas_hop_more; + +typedef union { + c3_y sot_u[6]; + u3_xmas_hop_once one_u; + u3_xmas_hop_more man_u; +} u3_xmas_hop; + + +typedef struct _u3_xmas_page_pact { + u3_xmas_name nam_u; + u3_xmas_data dat_u; + union { + c3_y sot_u[6]; + u3_xmas_hop_once one_u; + u3_xmas_hop_more man_u; + }; +} u3_xmas_page_pact; + +typedef struct _u3_xmas_poke_pact { + u3_xmas_name nam_u; + u3_xmas_name pay_u; + u3_xmas_data dat_u; +} u3_xmas_poke_pact; + +typedef struct _u3_xmas_pact { + u3_xmas_head hed_u; + union { + u3_xmas_poke_pact pok_u; + u3_xmas_page_pact pag_u; + u3_xmas_peek_pact pek_u; + }; +} u3_xmas_pact; + +c3_w xmas_sift_pact(u3_xmas_pact* pac_u, c3_y* buf_y, c3_w len_w); +c3_w xmas_etch_pact(c3_y* buf_y, u3_xmas_pact* pac_u); + +void xmas_free_pact(u3_xmas_pact* pac_u); + +void log_pact(u3_xmas_pact* pac_u); + +#endif \ No newline at end of file diff --git a/pkg/vere/pact_tests.c b/pkg/vere/pact_tests.c new file mode 100644 index 0000000000..76fd0835e6 --- /dev/null +++ b/pkg/vere/pact_tests.c @@ -0,0 +1,477 @@ +/// @file + +#include "./io/xmas/pact.c" + +#define cmp_scalar(nam, str, fmt) \ + if ( hav_u->nam != ned_u->nam ) { \ + fprintf(stderr, "xmas test cmp " str " differ:\r\n" \ + " have: " fmt "\r\n" \ + " need: " fmt "\r\n", \ + hav_u->nam, ned_u->nam); \ + ret_i = 1; \ + } + +#define cmp_string(nam, siz, str) \ + if ( memcmp(hav_u->nam, ned_u->nam, siz) ) { \ + fprintf(stderr, "xmas test cmp " str " differ:\r\n" \ + " have: %*.s\r\n" \ + " need: %*.s\r\n", \ + siz, hav_u->nam, siz, ned_u->nam); \ + ret_i = 1; \ + } + +#define cmp_buffer(nam, siz, str) \ + if ( memcmp(hav_u->nam, ned_u->nam, siz) ) { \ + fprintf(stderr, "xmas test cmp " str "\r\n"); \ + ret_i = 1; \ + } + +static c3_i +_test_cmp_head(u3_xmas_head* hav_u, u3_xmas_head* ned_u) +{ + c3_i ret_i = 0; + + cmp_scalar(nex_y, "head: next", "%u"); + cmp_scalar(pro_y, "head: protocol", "%u"); + cmp_scalar(typ_y, "head: type", "%u"); + cmp_scalar(hop_y, "head: hop", "%u"); + cmp_scalar(mug_w, "head: mug", "%u"); + + return ret_i; +} + +static c3_i +_test_cmp_name(u3_xmas_name* hav_u, u3_xmas_name* ned_u) +{ + c3_i ret_i = 0; + + cmp_buffer(her_d, sizeof(ned_u->her_d), "name: ships differ"); + + cmp_scalar(rif_w, "name: rifts", "%u"); + cmp_scalar(boq_y, "name: bloqs", "%u"); + cmp_scalar(nit_o, "name: inits", "%u"); + cmp_scalar(aut_o, "name: auths", "%u"); + cmp_scalar(fra_w, "name: fragments", "%u"); + cmp_scalar(pat_s, "name: path-lengths", "%u"); + + cmp_string(pat_c, ned_u->pat_s, "name: paths"); + + return ret_i; +} + +static c3_i +_test_cmp_data(u3_xmas_data* hav_u, u3_xmas_data* ned_u) +{ + c3_i ret_i = 0; + + cmp_scalar(tot_w, "data: total packets", "%u"); + + cmp_scalar(aum_u.typ_e, "data: auth-types", "%u"); + cmp_buffer(aum_u.sig_y, 64, "data: sig|hmac|null"); + + cmp_scalar(aup_u.len_y, "data: hash-lengths", "%u"); + cmp_buffer(aup_u.has_y, ned_u->aup_u.len_y, "data: hashes"); + + cmp_scalar(len_w, "data: fragments-lengths", "%u"); + cmp_buffer(fra_y, ned_u->len_w, "data: fragments"); + + return ret_i; +} + +static c3_i +_test_pact(u3_xmas_pact* pac_u) +{ + c3_y* buf_y = c3_calloc(PACT_SIZE); + c3_w len_w = xmas_etch_pact(buf_y, pac_u); + c3_i ret_i = 0; + c3_i bot_i = 0; + c3_w sif_w; + + u3_xmas_pact nex_u; + memset(&nex_u, 0, sizeof(u3_xmas_pact)); + + if ( !len_w ) { + fprintf(stderr, "pact: etch failed\r\n"); + ret_i = 1; goto done; + } + else if ( len_w > PACT_SIZE ) { + fprintf(stderr, "pact: etch overflowed: %u\r\n", len_w); + ret_i = 1; goto done; + } + + if ( len_w != (sif_w = xmas_sift_pact(&nex_u, buf_y, len_w)) ) { + fprintf(stderr, "pact: sift failed len=%u sif=%u\r\n", len_w, sif_w); + _log_buf(buf_y, len_w); + ret_i = 1; goto done; + } + + bot_i = 1; + + if ( _test_cmp_head(&nex_u.hed_u, &pac_u->hed_u) ) { + fprintf(stderr, "pact: head cmp fail\r\n"); + ret_i = 1; + } + + switch ( pac_u->hed_u.typ_y ) { + case PACT_PEEK: { + if ( _test_cmp_name(&nex_u.pek_u.nam_u, &pac_u->pek_u.nam_u) ) { + fprintf(stderr, "%%peek name cmp fail\r\n"); + ret_i = 1; + } + } break; + + case PACT_PAGE: { + if ( _test_cmp_name(&nex_u.pag_u.nam_u, &pac_u->pag_u.nam_u) ) { + fprintf(stderr, "%%page name cmp fail\r\n"); + ret_i = 1; + } + else if ( _test_cmp_data(&nex_u.pag_u.dat_u, &pac_u->pag_u.dat_u) ) { + fprintf(stderr, "%%page data cmp fail\r\n"); + ret_i = 1; + } + } break; + + case PACT_POKE: { + if ( _test_cmp_name(&nex_u.pok_u.nam_u, &pac_u->pok_u.nam_u) ) { + fprintf(stderr, "%%poke name cmp fail\r\n"); + ret_i = 1; + } + else if ( _test_cmp_name(&nex_u.pok_u.pay_u, &pac_u->pok_u.pay_u) ) { + fprintf(stderr, "%%poke pay-name cmp fail\r\n"); + ret_i = 1; + } + else if ( _test_cmp_data(&nex_u.pok_u.dat_u, &pac_u->pok_u.dat_u) ) { + fprintf(stderr, "%%poke data cmp fail\r\n"); + ret_i = 1; + } + } break; + + default: { + fprintf(stderr, "test: strange packet\r\n"); + ret_i = 1; + } + } + +done: + if ( ret_i ) { + _log_head(&pac_u->hed_u); + _log_pact(pac_u); + _log_buf(buf_y, len_w); + + if ( bot_i ) { + u3l_log(RED_TEXT); + _log_head(&nex_u.hed_u); + _log_pact(&nex_u); + u3l_log(DEF_TEXT); + } + } + + c3_free(buf_y); + + return ret_i; +} + +static c3_y +_test_rand_bit(void* ptr_v) +{ + return rand() & 1; +} + +static c3_y +_test_rand_bits(void* ptr_v, c3_y len_y) +{ + assert( 8 >= len_y ); + return rand() & ((1 << len_y) - 1); +} + +static c3_w +_test_rand_word(void* ptr_v) +{ + c3_w low_w = rand(); + c3_w hig_w = rand(); + return (hig_w << 16) ^ (low_w & ((1 << 16) - 1)); +} + +static c3_y +_test_rand_gulf_y(void* ptr_v, c3_y top_y) +{ + c3_y bit_y = c3_bits_word(top_y); + c3_y res_y = 0; + + if ( !bit_y ) return res_y; + + while ( 1 ) { + res_y = _test_rand_bits(ptr_v, bit_y); + + if ( res_y < top_y ) { + return res_y; + } + } +} + +static c3_w +_test_rand_gulf_w(void* ptr_v, c3_w top_w) +{ + c3_w bit_w = c3_bits_word(top_w); + c3_w res_w = 0; + + if ( !bit_w ) return res_w; + + while ( 1 ) { + res_w = _test_rand_word(ptr_v); + res_w &= (1 << bit_w) - 1; + + if ( res_w < top_w ) { + return res_w; + } + } +} + +static void +_test_rand_bytes(void* ptr_v, c3_w len_w, c3_y* buf_y) +{ + c3_w max_w = len_w / 2; + + while ( max_w-- ) { + c3_w wor_w = rand(); + *buf_y++ = (wor_w >> 0) & 0xff; + *buf_y++ = (wor_w >> 8) & 0xff; + } + + if ( len_w & 1 ) { + *buf_y = rand() & 0xff; + } +} + +const char* ta_c = "-~_.0123456789abcdefghijklmnopqrstuvwxyz"; + +static void +_test_rand_knot(void* ptr_v, c3_w len_w, c3_c* not_c) +{ + for ( c3_w i_w = 0; i_w < len_w; i_w++ ) { + *not_c++ = ta_c[_test_rand_gulf_y(ptr_v, 40)]; + } +} + +static void +_test_rand_path(void* ptr_v, c3_s len_s, c3_c* pat_c) +{ + c3_s not_s = 0; + + while ( len_s ) { + not_s = _test_rand_gulf_w(ptr_v, len_s); + _test_rand_knot(ptr_v, not_s, pat_c); + pat_c[not_s] = '/'; + pat_c += not_s + 1; + len_s -= not_s + 1; + } +} + +static void +_test_make_head(void* ptr_v, u3_xmas_head* hed_u) +{ + hed_u->nex_y = NEXH_NONE; // XX + hed_u->pro_y = 1; + hed_u->typ_y = _test_rand_gulf_y(ptr_v, 3) + 1; + hed_u->hop_y = _test_rand_gulf_y(ptr_v, 8); + hed_u->mug_w = 0; + // XX set mug_w in etch? +} + +static void +_test_make_name(void* ptr_v, c3_s pat_s, u3_xmas_name* nam_u) +{ + _test_rand_bytes(ptr_v, 16, (c3_y*)nam_u->her_d); + nam_u->rif_w = _test_rand_word(ptr_v); + + nam_u->pat_s = _test_rand_gulf_w(ptr_v, pat_s); + nam_u->pat_c = c3_malloc(nam_u->pat_s + 1); + _test_rand_path(ptr_v, nam_u->pat_s, nam_u->pat_c); + nam_u->pat_c[nam_u->pat_s] = 0; + + nam_u->boq_y = _test_rand_bits(ptr_v, 8); + nam_u->nit_o = _test_rand_bits(ptr_v, 1); + + if ( c3y == nam_u->nit_o ) { + nam_u->aut_o = c3n; + nam_u->fra_w = 0; + } + else { + nam_u->aut_o = _test_rand_bits(ptr_v, 1); + nam_u->fra_w = _test_rand_word(ptr_v); + } +} + +static void +_test_make_data(void* ptr_v, u3_xmas_data* dat_u) +{ + dat_u->tot_w = _test_rand_word(ptr_v); + + memset(dat_u->aum_u.sig_y, 0, 64); + dat_u->aup_u.len_y = 0; + memset(dat_u->aup_u.has_y, 0, sizeof(dat_u->aup_u.has_y)); + + switch ( dat_u->aum_u.typ_e = _test_rand_bits(ptr_v, 2) ) { + case AUTH_NEXT: { + dat_u->aup_u.len_y = 2; + } break; + + case AUTH_SIGN: { + dat_u->aup_u.len_y = _test_rand_gulf_y(ptr_v, 3); + _test_rand_bytes(ptr_v, 64, dat_u->aum_u.sig_y); + } break; + + case AUTH_HMAC: { + dat_u->aup_u.len_y = _test_rand_gulf_y(ptr_v, 3); + _test_rand_bytes(ptr_v, 32, dat_u->aum_u.mac_y); + } break; + + default: break; + } + + for ( c3_w i_w = 0; i_w < dat_u->aup_u.len_y; i_w++ ) { + _test_rand_bytes(ptr_v, 32, dat_u->aup_u.has_y[i_w]); + } + + dat_u->len_w = _test_rand_gulf_w(ptr_v, 1024); + dat_u->fra_y = c3_calloc(dat_u->len_w); + _test_rand_bytes(ptr_v, dat_u->len_w, dat_u->fra_y); +} + +static void +_test_make_pact(void* ptr_v, u3_xmas_pact* pac_u) +{ + _test_make_head(ptr_v, &pac_u->hed_u); + + switch ( pac_u->hed_u.typ_y ) { + case PACT_PEEK: { + _test_make_name(ptr_v, 277, &pac_u->pek_u.nam_u); + } break; + + case PACT_PAGE: { + _test_make_name(ptr_v, 277, &pac_u->pag_u.nam_u); + _test_make_data(ptr_v, &pac_u->pag_u.dat_u); + } break; + + case PACT_POKE: { + _test_make_name(ptr_v, 124, &pac_u->pok_u.nam_u); + _test_make_name(ptr_v, 124, &pac_u->pok_u.pay_u); + _test_make_data(ptr_v, &pac_u->pok_u.dat_u); + } break; + + default: break; // XX + } +} + +static c3_i +_test_rand_pact(c3_w bat_w) +{ + u3_xmas_pact pac_u; + void* ptr_v = 0; + + fprintf(stderr, "pact: test roundtrip %u random packets\r\n", bat_w); + + for ( c3_w i_w = 0; i_w < bat_w; i_w++ ) { + _test_make_pact(ptr_v, &pac_u); + + if ( _test_pact(&pac_u) ) { + fprintf(stderr, RED_TEXT "pact: roundtrip attempt %u failed\r\n", i_w); + exit(1); + } + + // XX free pat_s / buf_y + } + + return 0; +} + +static void +_test_sift_page() +{ + u3_xmas_pact pac_u; + memset(&pac_u,0, sizeof(u3_xmas_pact)); + pac_u.hed_u.typ_y = PACT_PAGE; + pac_u.hed_u.pro_y = 1; + u3l_log("%%page checking sift/etch idempotent"); + u3_xmas_name* nam_u = &pac_u.pag_u.nam_u; + + { + u3_noun her = u3v_wish("~hastuc-dibtux"); + u3r_chubs(0, 2, nam_u->her_d, her); + u3z(her); + } + nam_u->rif_w = 15; + nam_u->pat_c = "foo/bar"; + nam_u->pat_s = strlen(nam_u->pat_c); + nam_u->boq_y = 13; + nam_u->fra_w = 54; + nam_u->nit_o = c3n; + + u3_xmas_data* dat_u = &pac_u.pag_u.dat_u; + dat_u->aum_u.typ_e = AUTH_NONE; + dat_u->tot_w = 1000; + dat_u->len_w = 1024; + dat_u->fra_y = c3_calloc(1024); + // dat_u->fra_y[1023] = 1; + + if ( _test_pact(&pac_u) ) { + fprintf(stderr, RED_TEXT "%%page failed\r\n"); + exit(1); + } +} + + +static void +_test_encode_path(c3_c* pat_c) +{ + u3_noun wan = u3do("stab", u3dt("cat", 3, '/', u3i_string(pat_c))); + u3_noun hav = u3_xmas_encode_path(strlen(pat_c), (c3_y*)pat_c); + + if ( c3n == u3r_sing(wan, hav) ) { + u3l_log(RED_TEXT); + u3l_log("path encoding mismatch"); + u3m_p("want", wan); + u3m_p("have", hav); + exit(1); + } +} + + +static void +_setup() +{ + c3_d len_d = u3_Ivory_pill_len; + c3_y* byt_y = u3_Ivory_pill; + u3_cue_xeno* sil_u; + u3_weak pil; + + u3C.wag_w |= u3o_hashless; + u3m_boot_lite(1 << 26); + sil_u = u3s_cue_xeno_init_with(ur_fib27, ur_fib28); + if ( u3_none == (pil = u3s_cue_xeno_with(sil_u, len_d, byt_y)) ) { + printf("*** fail _setup 1\n"); + exit(1); + } + u3s_cue_xeno_done(sil_u); + if ( c3n == u3v_boot_lite(pil) ) { + printf("*** fail _setup 2\n"); + exit(1); + } + + { + c3_w pid_w = getpid(); + srand(pid_w); + fprintf(stderr, "test: seeding rand() with pid %u\r\n", pid_w); + } +} + +int main() +{ + _setup(); + + _test_rand_pact(100000); + + _test_encode_path("foo/bar/baz"); + _test_encode_path("publ/0/xx//1/foo/g"); + return 0; +} diff --git a/pkg/vere/serf.c b/pkg/vere/serf.c index cec8bece55..a99544b447 100644 --- a/pkg/vere/serf.c +++ b/pkg/vere/serf.c @@ -1054,7 +1054,7 @@ u3_serf_init(u3_serf* sef_u) { c3_w pro_w = 1; - c3_y hon_y = 139; + c3_y hon_y = 138; c3_y noc_y = 4; u3_noun ver = u3nt(pro_w, hon_y, noc_y); diff --git a/pkg/vere/vere.h b/pkg/vere/vere.h index 2b64e0c7c7..c9e7f19756 100644 --- a/pkg/vere/vere.h +++ b/pkg/vere/vere.h @@ -1236,6 +1236,17 @@ u3_noun u3_ames_encode_lane(u3_lane); + /** xmas + **/ + /* _xmas_io_init(): initialize new-ames I/O. + */ + u3_auto* + u3_xmas_io_init(u3_pier* pir_u); + + /* u3_xmas_encode_path(): + */ + u3_noun + u3_xmas_encode_path(c3_w len_w, c3_y* buf_y); /** Autosave. **/ /* u3_save_ef_chld(): report SIGCHLD. diff --git a/pkg/vere/xmas_tests.c b/pkg/vere/xmas_tests.c new file mode 100644 index 0000000000..5f6c008c2f --- /dev/null +++ b/pkg/vere/xmas_tests.c @@ -0,0 +1,60 @@ +/// @file + +#include "./io/xmas.c" + +/* _setup(): prepare for tests. +*/ +static void +_setup(void) +{ + u3m_init(1 << 22); + u3m_pave(c3y); +} + +/* _test_ames(): spot check ames helpers +*/ +static void +_test_xmas(void) +{ + u3_lane lan_u; + lan_u.pip_w = 0x7f000001; + lan_u.por_s = 12345; + + u3_noun lan = u3_ames_encode_lane(lan_u); + u3_lane nal_u = u3_ames_decode_lane(u3k(lan)); + u3_lane nal_u2 = u3_ames_decode_lane(lan); + + if ( !(lan_u.pip_w == nal_u.pip_w && lan_u.por_s == nal_u.por_s) ) { + fprintf(stderr, "ames: lane fail (a)\r\n"); + fprintf(stderr, "pip: %d, por: %d\r\n", nal_u.pip_w, nal_u.por_s); + exit(1); + } + + u3_xmas_name pok_u = (u3_xmas_name) { + .her_d = {43, 0}, + .rif_w = 1, + .boq_y = 13, + .nit_o = c3n, + .aut_o = c3n, + .fra_w = 1, + .pat_s = 8, + .pat_c = "/foo/bar" + }; +} + +/* main(): run all test cases. +*/ +int +main(int argc, char* argv[]) +{ + _setup(); + + _test_xmas(); + + // GC + // + u3m_grab(u3_none); + + fprintf(stderr, "xmas okeedokee\n"); + return 0; +}