static void adminPing(Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc) { struct Context* context = vcontext; String* pathStr = Dict_getString(args, String_CONST("path")); int64_t* timeoutPtr = Dict_getInt(args, String_CONST("timeout")); String* data = Dict_getString(args, String_CONST("data")); int64_t* keyPing = Dict_getInt(args, String_CONST("keyPing")); uint32_t timeout = (timeoutPtr) ? *timeoutPtr : DEFAULT_TIMEOUT; uint64_t path; String* err = NULL; if (pathStr->len != 19 || AddrTools_parsePath(&path, (uint8_t*) pathStr->bytes)) { err = String_CONST("path was not parsable."); } else { struct SwitchPinger_Ping* ping = SwitchPinger_newPing(path, data, timeout, adminPingOnResponse, context->alloc, context->switchPinger); if (keyPing && *keyPing) { ping->keyPing = true; } if (!ping) { err = String_CONST("no open slots to store ping, try later."); } else { ping->onResponseContext = Allocator_clone(ping->pingAlloc, (&(struct Ping) { .context = context, .txid = String_clone(txid, ping->pingAlloc), .path = String_clone(pathStr, ping->pingAlloc) })); } }
static void getRouteLabel(Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc) { struct Context* ctx = Identity_check((struct Context*) vcontext); char* err = NULL; String* pathToParentS = Dict_getString(args, String_CONST("pathToParent")); uint64_t pathToParent = 0; if (pathToParentS->len != 19 || AddrTools_parsePath(&pathToParent, pathToParentS->bytes)) { err = "parse_pathToParent"; } String* pathParentToChildS = Dict_getString(args, String_CONST("pathParentToChild")); uint64_t pathParentToChild = 0; if (pathParentToChildS->len != 19 || AddrTools_parsePath(&pathParentToChild, pathParentToChildS->bytes)) { err = "parse_pathParentToChild"; } uint64_t label = UINT64_MAX; if (!err) { label = NodeStore_getRouteLabel(ctx->store, pathToParent, pathParentToChild); err = NodeStore_getRouteLabel_strerror(label); } Dict* response = Dict_new(requestAlloc); if (!err) { String* printedPath = String_newBinary(NULL, 19, requestAlloc); AddrTools_printPath(printedPath->bytes, label); Dict_putString(response, String_new("result", requestAlloc), printedPath, requestAlloc); Dict_putString(response, String_new("error", requestAlloc), String_new("none", requestAlloc), requestAlloc); Admin_sendMessage(response, txid, ctx->admin); } else { Dict_putString(response, String_new("error", requestAlloc), String_new(err, requestAlloc), requestAlloc); Admin_sendMessage(response, txid, ctx->admin); } }
static struct Address* getNode(String* pathStr, struct Context* ctx, char** errOut, struct Allocator* alloc) { struct Address addr = {.path=0}; if (pathStr->len == 19 && !AddrTools_parsePath(&addr.path, pathStr->bytes)) { struct Node_Link* nl = Router_linkForPath(ctx->router, addr.path); if (!nl) { *errOut = "not_found"; return NULL; } else { Bits_memcpyConst(&addr, &nl->child->address, sizeof(struct Address)); } } else if (pathStr->len == 39 && !AddrTools_parseIp(addr.ip6.bytes, pathStr->bytes)) { struct Node_Two* n = Router_lookup(ctx->router, addr.ip6.bytes); if (!n || Bits_memcmp(addr.ip6.bytes, n->address.ip6.bytes, 16)) { *errOut = "not_found"; return NULL; } else { Bits_memcpyConst(&addr, &n->address, sizeof(struct Address)); } } else { struct Address* a = Address_fromString(pathStr, alloc); if (a) { return a; } *errOut = "parse_path"; return NULL; } return Allocator_clone(alloc, &addr); } static void pingNode(Dict* args, void* vctx, String* txid, struct Allocator* requestAlloc) { struct Context* ctx = Identity_check((struct Context*) vctx); String* pathStr = Dict_getString(args, String_CONST("path")); int64_t* timeoutPtr = Dict_getInt(args, String_CONST("timeout")); uint32_t timeout = (timeoutPtr && *timeoutPtr > 0) ? *timeoutPtr : 0; char* err = NULL; struct Address* addr = getNode(pathStr, ctx, &err, requestAlloc); if (err) { Dict errDict = Dict_CONST(String_CONST("error"), String_OBJ(String_CONST(err)), NULL); Admin_sendMessage(&errDict, txid, ctx->admin); return; } struct RouterModule_Promise* rp = RouterModule_pingNode(addr, timeout, ctx->module, ctx->allocator); struct Ping* ping = Allocator_calloc(rp->alloc, sizeof(struct Ping), 1); Identity_set(ping); ping->txid = String_clone(txid, rp->alloc); ping->rp = rp; ping->ctx = ctx; rp->userData = ping; rp->callback = pingResponse; } static void getPeers(Dict* args, void* vctx, String* txid, struct Allocator* requestAlloc) { struct Context* ctx = Identity_check((struct Context*) vctx); String* nearbyLabelStr = Dict_getString(args, String_CONST("nearbyPath")); String* pathStr = Dict_getString(args, String_CONST("path")); int64_t* timeoutPtr = Dict_getInt(args, String_CONST("timeout")); uint32_t timeout = (timeoutPtr && *timeoutPtr > 0) ? *timeoutPtr : 0; char* err = NULL; struct Address* addr = getNode(pathStr, ctx, &err, requestAlloc); uint64_t nearbyLabel = 0; if (!err && nearbyLabelStr) { if (nearbyLabelStr->len != 19 || AddrTools_parsePath(&nearbyLabel, nearbyLabelStr->bytes)) { err = "parse_nearbyLabel"; } } if (err) { Dict errDict = Dict_CONST(String_CONST("error"), String_OBJ(String_CONST(err)), NULL); Admin_sendMessage(&errDict, txid, ctx->admin); return; } struct RouterModule_Promise* rp = RouterModule_getPeers(addr, nearbyLabel, timeout, ctx->module, ctx->allocator); struct Ping* ping = Allocator_calloc(rp->alloc, sizeof(struct Ping), 1); Identity_set(ping); ping->txid = String_clone(txid, rp->alloc); ping->rp = rp; ping->ctx = ctx; rp->userData = ping; rp->callback = getPeersResponse; } static void findNode(Dict* args, void* vctx, String* txid, struct Allocator* requestAlloc) { struct Context* ctx = Identity_check((struct Context*) vctx); String* nodeToQueryStr = Dict_getString(args, String_CONST("nodeToQuery")); String* targetStr = Dict_getString(args, String_CONST("target")); int64_t* timeoutPtr = Dict_getInt(args, String_CONST("timeout")); uint32_t timeout = (timeoutPtr && *timeoutPtr > 0) ? *timeoutPtr : 0; char* err = NULL; struct Address* nodeToQuery = getNode(nodeToQueryStr, ctx, &err, requestAlloc); uint8_t target[16]; if (!err) { if (targetStr->len != 39 || AddrTools_parseIp(target, targetStr->bytes)) { err = "parse_target"; } } if (err) { Dict errDict = Dict_CONST(String_CONST("error"), String_OBJ(String_CONST(err)), NULL); Admin_sendMessage(&errDict, txid, ctx->admin); return; } struct RouterModule_Promise* rp = RouterModule_findNode(nodeToQuery, target, timeout, ctx->module, ctx->allocator); struct Ping* ping = Allocator_calloc(rp->alloc, sizeof(struct Ping), 1); Identity_set(ping); ping->txid = String_clone(txid, rp->alloc); ping->rp = rp; ping->ctx = ctx; rp->userData = ping; rp->callback = findNodeResponse; } void RouterModule_admin_register(struct RouterModule* module, struct Router* router, struct Admin* admin, struct Allocator* alloc) { // for improved reporting alloc = Allocator_child(alloc); struct Context* ctx = Allocator_clone(alloc, (&(struct Context) { .admin = admin, .allocator = alloc, .module = module, .router = router }));
static void pingNode(Dict* args, void* vctx, String* txid, struct Allocator* requestAlloc) { struct Context* ctx = Identity_cast((struct Context*) vctx); String* pathStr = Dict_getString(args, String_CONST("path")); int64_t* timeoutPtr = Dict_getInt(args, String_CONST("timeout")); uint32_t timeout = (timeoutPtr && *timeoutPtr > 0) ? *timeoutPtr : 0; char* err = NULL; struct Address addr = {.path=0}; struct Node* n = NULL; if (pathStr->len == 19 && !AddrTools_parsePath(&addr.path, (uint8_t*) pathStr->bytes)) { n = RouterModule_getNode(addr.path, ctx->router); } else if (!AddrTools_parseIp(addr.ip6.bytes, (uint8_t*) pathStr->bytes)) { n = RouterModule_lookup(addr.ip6.bytes, ctx->router); if (n && Bits_memcmp(addr.ip6.bytes, n->address.ip6.bytes, 16)) { n = NULL; } } else { err = "Unexpected address, must be either an ipv6 address " "eg: 'fc4f:d:e499:8f5b:c49f:6e6b:1ae:3120', 19 char path eg: '0123.4567.89ab.cdef'"; } if (!err) { if (!n) { err = "could not find node to ping"; } else { struct RouterModule_Promise* rp = RouterModule_pingNode(n, timeout, ctx->router, ctx->allocator); struct Ping* ping = Allocator_calloc(rp->alloc, sizeof(struct Ping), 1); Identity_set(ping); ping->txid = String_clone(txid, rp->alloc); ping->rp = rp; ping->ctx = ctx; rp->userData = ping; rp->callback = pingResponse; } } if (err) { Dict errDict = Dict_CONST(String_CONST("error"), String_OBJ(String_CONST(err)), NULL); Admin_sendMessage(&errDict, txid, ctx->admin); } } void RouterModule_admin_register(struct RouterModule* module, struct Admin* admin, struct Allocator* alloc) { struct Context* ctx = Allocator_clone(alloc, (&(struct Context) { .admin = admin, .allocator = alloc, .router = module })); Identity_set(ctx); Admin_registerFunction("RouterModule_lookup", lookup, ctx, true, ((struct Admin_FunctionArg[]) { { .name = "address", .required = 1, .type = "String" } }), admin);
static void dumpTable_addEntries(struct Context* ctx, int i, int j, struct List_Item* last, String* txid) { uint8_t path[20]; uint8_t ip[40]; String* pathStr = &(String) { .len = 19, .bytes = (char*)path }; String* ipStr = &(String) { .len = 39, .bytes = (char*)ip }; Object* link = Int_OBJ(0xFFFFFFFF); Object* version = Int_OBJ(Version_DEFAULT_ASSUMPTION); Dict entry = Dict_CONST( String_CONST("ip"), String_OBJ(ipStr), Dict_CONST( String_CONST("link"), link, Dict_CONST( String_CONST("path"), String_OBJ(pathStr), Dict_CONST( String_CONST("version"), version, NULL )))); struct List_Item next = { .next = last, .elem = Dict_OBJ(&entry) }; if (i >= ctx->store->size || j >= ENTRIES_PER_PAGE) { if (i > j) { dumpTable_send(ctx, last, (j >= ENTRIES_PER_PAGE), txid); return; } Address_printIp(ip, ctx->store->selfAddress); strcpy((char*)path, "0000.0000.0000.0001"); version->as.number = Version_CURRENT_PROTOCOL; dumpTable_send(ctx, &next, (j >= ENTRIES_PER_PAGE), txid); return; } struct Node* n = NodeStore_dumpTable(ctx->store, i); link->as.number = n->reach; version->as.number = n->version; Address_printIp(ip, &n->address); AddrTools_printPath(path, n->address.path); dumpTable_addEntries(ctx, i + 1, j + 1, &next, txid); } static void dumpTable(Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc) { struct Context* ctx = Identity_cast((struct Context*) vcontext); int64_t* page = Dict_getInt(args, String_CONST("page")); int i = (page) ? *page * ENTRIES_PER_PAGE : 0; dumpTable_addEntries(ctx, i, 0, NULL, txid); } static bool isOneHop(struct Node_Link* link) { struct EncodingScheme* ps = link->parent->encodingScheme; int num = EncodingScheme_getFormNum(ps, link->cannonicalLabel); Assert_always(num > -1 && num < ps->count); return EncodingScheme_formSize(&ps->forms[num]) == Bits_log2x64(link->cannonicalLabel); } static void getLink(Dict* args, void* vcontext, String* txid, struct Allocator* alloc) { struct Context* ctx = Identity_cast((struct Context*) vcontext); Dict* ret = Dict_new(alloc); Dict* result = Dict_new(alloc); Dict_putDict(ret, String_new("result", alloc), result, alloc); Dict_putString(ret, String_new("error", alloc), String_new("none", alloc), alloc); struct Node_Link* link; String* ipStr = Dict_getString(args, String_new("parent", alloc)); int64_t* linkNum = Dict_getInt(args, String_new("linkNum", alloc)); uint8_t ip[16]; if (ipStr->len != 39 || AddrTools_parseIp(ip, ipStr->bytes)) { Dict_remove(ret, String_CONST("result")); Dict_putString(ret, String_new("error", alloc), String_new("Could not parse ip", alloc), alloc); } else if ((link = NodeStore_getLink(ctx->store, ip, *linkNum))) { Dict_putInt(result, String_new("inverseLinkEncodingFormNumber", alloc), link->inverseLinkEncodingFormNumber, alloc); Dict_putInt(result, String_new("linkState", alloc), link->linkState, alloc); Dict_putInt(result, String_new("isOneHop", alloc), isOneHop(link), alloc); String* cannonicalLabel = String_newBinary(NULL, 19, alloc); AddrTools_printPath(cannonicalLabel->bytes, link->cannonicalLabel); Dict_putString(result, String_new("cannonicalLabel", alloc), cannonicalLabel, alloc); String* parent = String_newBinary(NULL, 39, alloc); AddrTools_printIp(parent->bytes, link->parent->address.ip6.bytes); Dict_putString(result, String_new("parent", alloc), parent, alloc); String* child = String_newBinary(NULL, 39, alloc); AddrTools_printIp(child->bytes, link->child->address.ip6.bytes); Dict_putString(result, String_new("child", alloc), child, alloc); } Admin_sendMessage(ret, txid, ctx->admin); } static void getNode(Dict* args, void* vcontext, String* txid, struct Allocator* alloc) { struct Context* ctx = Identity_cast((struct Context*) vcontext); Dict* ret = Dict_new(alloc); Dict* result = Dict_new(alloc); Dict_putDict(ret, String_new("result", alloc), result, alloc); Dict_putString(ret, String_new("error", alloc), String_new("none", alloc), alloc); // no ipStr specified --> return self-node struct Node_Two* node = ctx->store->selfNode; String* ipStr = Dict_getString(args, String_new("ip", alloc)); uint8_t ip[16]; while (ipStr) { if (ipStr->len != 39 || AddrTools_parseIp(ip, ipStr->bytes)) { Dict_remove(ret, String_CONST("result")); Dict_putString(ret, String_new("error", alloc), String_new("Could not parse ip", alloc), alloc); } else if (!(node = NodeStore_getNode2(ctx->store, ip))) { // not found } else { break; } Admin_sendMessage(ret, txid, ctx->admin); return; } Dict_putInt(result, String_new("protocolVersion", alloc), node->version, alloc); String* key = Key_stringify(node->address.key, alloc); Dict_putString(result, String_new("key", alloc), key, alloc); uint32_t linkCount = NodeStore_linkCount(node); Dict_putInt(result, String_new("linkCount", alloc), linkCount, alloc); List* encScheme = EncodingScheme_asList(node->encodingScheme, alloc); Dict_putList(result, String_new("encodingScheme", alloc), encScheme, alloc); Admin_sendMessage(ret, txid, ctx->admin); } static void getRouteLabel(Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc) { struct Context* ctx = Identity_cast((struct Context*) vcontext); char* err = NULL; String* pathToParentS = Dict_getString(args, String_CONST("pathToParent")); uint64_t pathToParent; if (pathToParentS->len != 19) { err = "pathToParent incorrect length"; } else if (AddrTools_parsePath(&pathToParent, pathToParentS->bytes)) { err = "Failed to parse pathToParent"; } String* childAddressS = Dict_getString(args, String_CONST("childAddress")); uint8_t childAddress[16]; if (childAddressS->len != 39) { err = "childAddress of incorrect length, must be a 39 character full ipv6 address"; } else if (AddrTools_parseIp(childAddress, childAddressS->bytes)) { err = "Failed to parse childAddress"; } uint64_t label = UINT64_MAX; if (!err) { label = NodeStore_getRouteLabel(ctx->store, pathToParent, childAddress); err = NodeStore_getRouteLabel_strerror(label); } Dict* response = Dict_new(requestAlloc); if (!err) { String* printedPath = String_newBinary(NULL, 19, requestAlloc); AddrTools_printPath(printedPath->bytes, label); Dict_putString(response, String_new("result", requestAlloc), printedPath, requestAlloc); Dict_putString(response, String_new("error", requestAlloc), String_new("none", requestAlloc), requestAlloc); Admin_sendMessage(response, txid, ctx->admin); } else { Dict_putString(response, String_new("error", requestAlloc), String_new(err, requestAlloc), requestAlloc); Admin_sendMessage(response, txid, ctx->admin); } } void NodeStore_admin_register(struct NodeStore* nodeStore, struct Admin* admin, struct Allocator* alloc) { struct Context* ctx = Allocator_clone(alloc, (&(struct Context) { .admin = admin, .alloc = alloc, .store = nodeStore })); Identity_set(ctx); Admin_registerFunction("NodeStore_dumpTable", dumpTable, ctx, false, ((struct Admin_FunctionArg[]) { { .name = "page", .required = 1, .type = "Int" }, }), admin); Admin_registerFunction("NodeStore_getLink", getLink, ctx, true, ((struct Admin_FunctionArg[]) { { .name = "parent", .required = 1, .type = "String" }, { .name = "linkNum", .required = 1, .type = "Int" }, }), admin);