Esempio n. 1
0
/** Called when the request allocator is freed. */
static int removeReqFromSet(struct Allocator_OnFreeJob* job)
{
    struct Request* req = Identity_cast((struct Request*) job->userData);
    struct Hermes* h = Identity_cast(req->hermes);
    int index = Map_RequestSet_indexForHandle(req->handle, &h->requestSet);
    if (index > -1) {
        Map_RequestSet_remove(index, &h->requestSet);
    } else {
        Log_error(h->logger, "request with handle [%u] missing from set", req->handle);
    }
    return 0;
}
Esempio n. 2
0
int EventBase_eventCount(struct EventBase* eventBase)
{
    int eventCount = 0;
    struct EventBase_pvt* ctx = Identity_cast((struct EventBase_pvt*) eventBase);
    uv_walk(ctx->loop, countCallback, &eventCount);
    return eventCount;
}
Esempio n. 3
0
/** @see Allocator->onFree() */
static void* addOnFreeJob(void (* callback)(void* callbackContext),
                          void* callbackContext,
                          const struct Allocator* allocator)
{
    struct CanaryAllocator_pvt* ctx = Identity_cast((struct CanaryAllocator_pvt*) allocator);
    return ctx->alloc->onFree(callback, callbackContext, ctx->alloc);
}
Esempio n. 4
0
/** @see Allocator_child() */
static struct Allocator* childAllocator(const struct Allocator* allocator,
                                        const char* identFile,
                                        int identLine)
{
    struct CanaryAllocator_pvt* ctx = Identity_cast((struct CanaryAllocator_pvt*) allocator);
    return CanaryAllocator_new(ctx->alloc->child(ctx->alloc, identFile, identLine), ctx->rand);
}
Esempio n. 5
0
int32_t CryptoAuth_addUser(String* password,
                           uint8_t authType,
                           void* user,
                           struct CryptoAuth* ca)
{
    struct CryptoAuth_pvt* context = Identity_cast((struct CryptoAuth_pvt*) ca);
    if (authType != 1) {
        return CryptoAuth_addUser_INVALID_AUTHTYPE;
    }
    if (context->passwordCount == context->passwordCapacity) {
        // TODO: realloc password space and increase buffer.
        return CryptoAuth_addUser_OUT_OF_SPACE;
    }
    struct CryptoAuth_Auth a;
    hashPassword_sha256(&a, password);
    for (uint32_t i = 0; i < context->passwordCount; i++) {
        if (!Bits_memcmp(a.secret, context->passwords[i].secret, 32)) {
            return CryptoAuth_addUser_DUPLICATE;
        }
    }
    a.user = user;
    Bits_memcpyConst(&context->passwords[context->passwordCount],
                     &a,
                     sizeof(struct CryptoAuth_Auth));
    context->passwordCount++;
    return 0;
}
Esempio n. 6
0
static uint8_t sendMessage(struct Message* message, struct Interface* iface)
{
    struct UDPAddrInterface_pvt* context =
        Identity_cast((struct UDPAddrInterface_pvt*) iface->senderContext);

    struct Sockaddr_storage addrStore;
    Message_pop(message, &addrStore, context->pub.addr->addrLen);
    Assert_true(addrStore.addr.addrLen == context->pub.addr->addrLen);

    if (Socket_sendto(context->socket,
                      message->bytes,
                      message->length,
                      0,
                      &addrStore.addr) < 0)
    {
        switch (Errno_get()) {
            case Errno_EMSGSIZE:
                return Error_OVERSIZE_MESSAGE;

            case Errno_ENOBUFS:
            case Errno_EAGAIN:
                return Error_LINK_LIMIT_EXCEEDED;

            default:;
                Log_info(context->logger, "Got error sending to socket [%s]",
                         Errno_getString());
        }
    }
    return 0;
}
static void onPingResponse(enum SwitchPinger_Result result,
                           uint64_t label,
                           String* data,
                           uint32_t millisecondsLag,
                           uint32_t version,
                           void* onResponseContext)
{
    if (SwitchPinger_Result_OK != result) {
        return;
    }
    struct IFCPeer* ep = Identity_cast((struct IFCPeer*) onResponseContext);
    struct Context* ic = ifcontrollerForPeer(ep);

    struct Address addr;
    Bits_memset(&addr, 0, sizeof(struct Address));
    Bits_memcpyConst(addr.key, CryptoAuth_getHerPublicKey(ep->cryptoAuthIf), 32);
    addr.path = ep->switchLabel;
    Log_debug(ic->logger, "got switch pong from node with version [%d]", version);
    RouterModule_addNode(ic->routerModule, &addr, version);

    #ifdef Log_DEBUG
        // This will be false if it times out.
        //Assert_true(label == ep->switchLabel);
        uint8_t path[20];
        AddrTools_printPath(path, label);
        uint8_t sl[20];
        AddrTools_printPath(sl, ep->switchLabel);
        Log_debug(ic->logger, "Received [%s] from lazy endpoint [%s]  [%s]",
                  SwitchPinger_resultString(result)->bytes, path, sl);
    #endif
}
// This is directly called from SwitchCore, message is not encrypted.
static uint8_t sendFromSwitch(struct Message* msg, struct Interface* switchIf)
{
    struct IFCPeer* ep = Identity_cast((struct IFCPeer*) switchIf);

    // This sucks but cryptoauth trashes the content when it encrypts
    // and we need to be capable of sending back a coherent error message.
    uint8_t top[255];
    uint8_t* messageBytes = msg->bytes;
    uint16_t padding = msg->padding;
    uint16_t len = (msg->length < 255) ? msg->length : 255;
    Bits_memcpy(top, msg->bytes, len);

    uint8_t ret = ep->cryptoAuthIf->sendMessage(msg, ep->cryptoAuthIf);

    // If this node is unresponsive then return an error.
    struct Context* ic = ifcontrollerForPeer(ep);
    uint64_t now = Time_currentTimeMilliseconds(ic->eventBase);
    if (ret || now - ep->timeOfLastMessage > ic->unresponsiveAfterMilliseconds)
    {
        msg->bytes = messageBytes;
        msg->padding = padding;
        msg->length = len;
        Bits_memcpy(msg->bytes, top, len);

        return ret ? ret : Error_UNDELIVERABLE;
    } else {
        /* Way way way too much noise
        Log_debug(ic->logger,  "Sending to neighbor, last message from this node was [%u] ms ago.",
                  (now - ep->timeOfLastMessage));
        */
    }

    return Error_NONE;
}
Esempio n. 9
0
static uint8_t sendTo(struct Message* msg, struct Interface* iface)
{
    struct TestFramework_Link* link =
        Identity_cast((struct TestFramework_Link*)iface->senderContext);

    struct Interface* dest;
    struct TestFramework* srcTf;
    if (&link->destIf == iface) {
        dest = &link->srcIf;
        srcTf = link->dest;
    } else if (&link->srcIf == iface) {
        dest = &link->destIf;
        srcTf = link->src;
    } else {
        Assert_always(false);
    }

    printf("Transferring message to [%p] - message length [%d]\n", (void*)dest, msg->length);

    // Store the original message and a copy of the original so they can be compared later.
    srcTf->lastMsgBackup = Message_clone(msg, srcTf->alloc);
    srcTf->lastMsg = msg;
    if (msg->alloc) {
        // If it's a message which was buffered inside of CryptoAuth then it will be freed
        // so by adopting the allocator we can hold it in memory.
        Allocator_adopt(srcTf->alloc, msg->alloc);
    }

    // Copy the original and send that to the other end.
    struct Message* sendMsg = Message_clone(msg, dest->allocator);
    return dest->receiveMessage(sendMsg, dest);
}
Esempio n. 10
0
/** @see Allocator->malloc() */
static void* allocatorMalloc(size_t size, const struct Allocator* allocator)
{
    struct CanaryAllocator_pvt* ctx = Identity_cast((struct CanaryAllocator_pvt*) allocator);
    // get it on an even number of ints.
    uint32_t* out = ctx->alloc->malloc(SIZE_BYTES(size), ctx->alloc);
    return newAllocation(ctx, out, SIZE_INTS(size));
}
// This is directly called from SwitchCore, message is not encrypted.
static uint8_t sendFromSwitch(struct Message* msg, struct Interface* switchIf)
{
    struct IFCPeer* ep = Identity_cast((struct IFCPeer*) switchIf);

    ep->bytesOut += msg->length;

    struct Context* ic = ifcontrollerForPeer(ep);
    uint8_t ret;
    uint64_t now = Time_currentTimeMilliseconds(ic->eventBase);
    if (now - ep->timeOfLastMessage > ic->unresponsiveAfterMilliseconds) {
        // XXX: This is a hack because if the time of last message exceeds the
        //      unresponsive time, we need to send back an error and that means
        //      mangling the message which would otherwise be in the queue.
        struct Allocator* tempAlloc = Allocator_child(ic->allocator);
        struct Message* toSend = Message_clone(msg, tempAlloc);
        ret = Interface_sendMessage(ep->cryptoAuthIf, toSend);
        Allocator_free(tempAlloc);
    } else {
        ret = Interface_sendMessage(ep->cryptoAuthIf, msg);
    }

    // If this node is unresponsive then return an error.
    if (ret || now - ep->timeOfLastMessage > ic->unresponsiveAfterMilliseconds) {
        return ret ? ret : Error_UNDELIVERABLE;
    } else {
        /* Way way way too much noise
        Log_debug(ic->logger,  "Sending to neighbor, last message from this node was [%u] ms ago.",
                  (now - ep->timeOfLastMessage));
        */
    }

    return Error_NONE;
}
Esempio n. 12
0
static void timeout(void* vrequest)
{
    struct Request* req = Identity_cast((struct Request*) vrequest);
    Dict resp = Dict_CONST(String_CONST("error"), String_OBJ(String_CONST("timeout")), NULL);
    req->onResponse(&resp, req->onResponseContext);
    Allocator_free(req->alloc);
}
Esempio n. 13
0
static uint8_t sendMessage(struct Message* message, struct Interface* iface)
{
    struct AddrInterfaceAdapter_pvt* context =
        Identity_cast((struct AddrInterfaceAdapter_pvt*) iface);

    Message_shift(message, -(context->pub.addr->addrLen), NULL);
    return Interface_sendMessage(context->wrapped, message);
}
Esempio n. 14
0
/**
 * Send an arbitrary message to the tun device.
 *
 * @param message to be sent, must be prefixed with IpTunnel_PacketInfoHeader.
 * @param iface an interface for which receiverContext is the ducttape.
 */
static uint8_t sendToTun(struct Message* message, struct Interface* iface)
{
    struct Ducttape_pvt* context = Identity_cast((struct Ducttape_pvt*)iface->receiverContext);
    if (context->userIf) {
        return context->userIf->sendMessage(message, context->userIf);
    }
    return 0;
}
Esempio n. 15
0
static uint8_t receiveMessage(struct Message* message, struct Interface* iface)
{
    struct AddrInterfaceAdapter_pvt* context =
        Identity_cast((struct AddrInterfaceAdapter_pvt*) iface->receiverContext);

    Message_push(message, context->pub.addr, context->pub.addr->addrLen, NULL);
    return Interface_receiveMessage(&context->pub.generic, message);
}
Esempio n. 16
0
static uint8_t receiveMessage(struct Message* msg, struct Interface* iface)
{
    struct Hermes* hermes = Identity_cast((struct Hermes*) iface->receiverContext);
    struct Allocator* alloc = Allocator_child(hermes->alloc);
    receiveMessage2(msg, hermes, alloc);
    Allocator_free(alloc);
    return 0;
}
Esempio n. 17
0
static int requestOnFree(struct Allocator_OnFreeJob* job)
{
    struct Request* req = Identity_cast((struct Request*) job->userData);
    int idx = Map_OfRequestByHandle_indexForHandle(req->handle, &req->ctx->outstandingRequests);
    if (idx > -1) {
        Map_OfRequestByHandle_remove(idx, &req->ctx->outstandingRequests);
    }
    return 0;
}
Esempio n. 18
0
static void noPeers(void* vtrace)
{
    struct RouteTracer_Trace* trace = Identity_cast((struct RouteTracer_Trace*)vtrace);
    // trace has stalled.
    if (trace->pub.callback) {
        trace->pub.callback(&trace->pub, 0, NULL, NULL);
    }
    Allocator_free(trace->pub.alloc);
}
Esempio n. 19
0
static uint8_t receiveMessage(struct Message* received, struct Interface* interface)
{
    struct CryptoAuth_Wrapper* wrapper =
        Identity_cast((struct CryptoAuth_Wrapper*) interface->receiverContext);

    union Headers_CryptoAuth* header = (union Headers_CryptoAuth*) received->bytes;

    if (received->length < (wrapper->authenticatePackets ? 20 : 4)) {
        cryptoAuthDebug0(wrapper, "Dropped runt");
        return Error_UNDERSIZE_MESSAGE;
    }
    Assert_true(received->padding >= 12 || "need at least 12 bytes of padding in incoming message");
    #ifdef Log_DEBUG
        Assert_true(!((uintptr_t)received->bytes % 4) || !"alignment fault");
    #endif
    Message_shift(received, -4);

    uint32_t nonce = Endian_bigEndianToHost32(header->nonce);

    if (wrapper->nextNonce < 5) {
        if (nonce > 3 && nonce != UINT32_MAX && knowHerKey(wrapper)) {
            cryptoAuthDebug(wrapper, "Trying final handshake step, nonce=%u\n", nonce);
            uint8_t secret[32];
            getSharedSecret(secret,
                            wrapper->secret,
                            wrapper->tempKey,
                            NULL,
                            wrapper->context->logger);

            // We'll optimistically advance the nextNonce value because decryptMessage()
            // passes the message on to the upper level and if this message causes a
            // response, we want the CA to be in ESTABLISHED state.
            // if the decryptMessage() call fails, we CryptoAuth_reset() it back.
            wrapper->nextNonce += 3;

            if (decryptMessage(wrapper, nonce, received, secret)) {
                cryptoAuthDebug0(wrapper, "Final handshake step succeeded");
                Bits_memcpyConst(wrapper->secret, secret, 32);
                return callReceivedMessage(wrapper, received);
            }
            CryptoAuth_reset(&wrapper->externalInterface);
            cryptoAuthDebug0(wrapper, "Final handshake step failed");
            return Error_UNDELIVERABLE;
        }
    } else if (nonce > 4) {
        if (decryptMessage(wrapper, nonce, received, wrapper->secret)) {
            return callReceivedMessage(wrapper, received);
        } else {
            cryptoAuthDebug0(wrapper, "Failed to decrypt message");
            return Error_UNDELIVERABLE;
        }
    } else {
        cryptoAuthDebug0(wrapper, "Received handshake message during established connection");
    }
    Message_shift(received, 4);
    return decryptHandshake(wrapper, nonce, received, header);
}
Esempio n. 20
0
static void closeInterface(void* vendpoint)
{
    struct IFCPeer* toClose = Identity_cast((struct IFCPeer*) vendpoint);

    struct Context* ic = ifcontrollerForPeer(toClose);

    int index = Map_OfIFCPeerByExernalIf_indexForHandle(toClose->handle, &ic->peerMap);
    Assert_true(index >= 0);
    Map_OfIFCPeerByExernalIf_remove(index, &ic->peerMap);
}
Esempio n. 21
0
static int closeInterface(struct Allocator_OnFreeJob* job)
{
    struct IFCPeer* toClose = Identity_cast((struct IFCPeer*) job->userData);

    struct Context* ic = ifcontrollerForPeer(toClose);

    int index = Map_OfIFCPeerByExernalIf_indexForHandle(toClose->handle, &ic->peerMap);
    Assert_true(index >= 0);
    Map_OfIFCPeerByExernalIf_remove(index, &ic->peerMap);
    return 0;
}
Esempio n. 22
0
File: Pipe.c Progetto: AdUser/cjdns
static void sendMessageCallback(uv_write_t* uvReq, int error)
{
    struct Pipe_WriteRequest_pvt* req = Identity_cast((struct Pipe_WriteRequest_pvt*) uvReq);
    if (error) {
        Log_info(req->pipe->pub.logger, "Failed to write to pipe [%s] [%s]",
                 req->pipe->pub.fullName, uv_strerror(error) );
    }
    req->pipe->queueLen -= req->msg->length;
    Assert_true(req->pipe->queueLen >= 0);
    Allocator_free(req->alloc);
}
Esempio n. 23
0
static int onFree(struct Allocator_OnFreeJob* job)
{
    struct EventBase_pvt* ctx = Identity_cast((struct EventBase_pvt*) job->userData);
    if (ctx->running) {
        // The job will be completed in EventLoop_beginLoop()
        ctx->onFree = job;
        EventBase_endLoop((struct EventBase*) ctx);
        return Allocator_ONFREE_ASYNC;
    } else {
        uv_loop_delete(ctx->loop);
        return 0;
    }
}
Esempio n. 24
0
struct RouterModule_Promise* RouteTracer_trace(uint64_t route,
                                               struct RouteTracer* routeTracer,
                                               struct Allocator* allocator)
{
    struct RouteTracer_pvt* tracer = Identity_cast((struct RouteTracer_pvt*)routeTracer);
    struct Allocator* alloc = Allocator_child(allocator);
    struct RouteTracer_Trace* trace = Allocator_clone(alloc, (&(struct RouteTracer_Trace) {
        .target = route,
        .tracer = tracer,
        .pub = {
            .alloc = alloc
        }
    }));
Esempio n. 25
0
static uint8_t sendMessage(struct Message* message, struct Interface* ethIf)
{
    struct ETHInterface* context = Identity_cast((struct ETHInterface*) ethIf);

    struct sockaddr_ll addr;
    Bits_memcpyConst(&addr, &context->addrBase, sizeof(struct sockaddr_ll));
    Message_pop(message, addr.sll_addr, 8);

    /* Cut down on the noise
    uint8_t buff[sizeof(addr) * 2 + 1] = {0};
    Hex_encode(buff, sizeof(buff), (uint8_t*)&addr, sizeof(addr));
    Log_debug(context->logger, "Sending ethernet frame to [%s]", buff);
    */

    // Check if we will have to pad the message and pad if necessary.
    int pad = 0;
    for (int length = message->length; length+2 < MIN_PACKET_SIZE; length += 8) {
        pad++;
    }
    if (pad > 0) {
        int length = message->length;
        Message_shift(message, pad*8);
        Bits_memset(message->bytes, 0, pad*8);
        Bits_memmove(message->bytes, &message->bytes[pad*8], length);
    }
    Assert_true(pad < 8);
    uint16_t padAndId_be = Endian_hostToBigEndian16((context->id << 3) | pad);
    Message_push(message, &padAndId_be, 2);

    if (sendto(context->socket,
               message->bytes,
               message->length,
               0,
               (struct sockaddr*) &addr,
               sizeof(struct sockaddr_ll)) < 0)
    {
        switch (errno) {
            case EMSGSIZE:
                return Error_OVERSIZE_MESSAGE;

            case ENOBUFS:
            case EAGAIN:
                return Error_LINK_LIMIT_EXCEEDED;

            default:;
                Log_info(context->logger, "Got error sending to socket [%s]", strerror(errno));
        }
    }
    return 0;
}
Esempio n. 26
0
static int closeInterface(struct Allocator_OnFreeJob* job)
{
    struct IFCPeer* toClose = Identity_cast((struct IFCPeer*) job->userData);

    struct Context* ic = ifcontrollerForPeer(toClose);

    // flush the peer from the table...
    RouterModule_brokenPath(toClose->switchLabel, ic->routerModule);

    int index = Map_OfIFCPeerByExernalIf_indexForHandle(toClose->handle, &ic->peerMap);
    Assert_true(index >= 0);
    Map_OfIFCPeerByExernalIf_remove(index, &ic->peerMap);
    return 0;
}
Esempio n. 27
0
static uint8_t receiveMessage(struct Message* msg, struct Interface* iface)
{
    struct Context* ctx = Identity_cast((struct Context*) iface->receiverContext);

    struct Sockaddr_storage source;
    Message_pop(msg, &source, ctx->targetAddr->addrLen, NULL);
    if (Bits_memcmp(&source, ctx->targetAddr, ctx->targetAddr->addrLen)) {
        Log_info(ctx->logger, "Got spurious message from [%s], expecting messages from [%s]",
                 Sockaddr_print(&source.addr, msg->alloc),
                 Sockaddr_print(ctx->targetAddr, msg->alloc));
        return 0;
    }

    // we don't yet know with which message this data belongs,
    // the message alloc lives the length of the message reception.
    struct Allocator* alloc = Allocator_child(msg->alloc);

    struct Reader* reader = ArrayReader_new(msg->bytes, msg->length, alloc);
    Dict* d = Dict_new(alloc);
    if (StandardBencSerializer_get()->parseDictionary(reader, alloc, d)) {
        return 0;
    }

    String* txid = Dict_getString(d, String_CONST("txid"));
    if (!txid || txid->len != 8) {
        return 0;
    }

    // look up the result
    uint32_t handle = ~0u;
    Hex_decode((uint8_t*)&handle, 4, txid->bytes, 8);
    int idx = Map_OfRequestByHandle_indexForHandle(handle, &ctx->outstandingRequests);
    if (idx < 0) {
        return 0;
    }

    struct Request* req = ctx->outstandingRequests.values[idx];

    // now this data will outlive the life of the message.
    Allocator_adopt(req->promise->alloc, alloc);

    req->res.responseDict = d;

    int len =
        (msg->length > AdminClient_MAX_MESSAGE_SIZE) ? AdminClient_MAX_MESSAGE_SIZE : msg->length;
    Bits_memset(req->res.messageBytes, 0, AdminClient_MAX_MESSAGE_SIZE);
    Bits_memcpy(req->res.messageBytes, msg->bytes, len);
    done(req, AdminClient_Error_NONE);
    return 0;
}
Esempio n. 28
0
List* CryptoAuth_getUsers(struct CryptoAuth* context, struct Allocator* alloc)
{
    struct CryptoAuth_pvt* ctx = Identity_cast((struct CryptoAuth_pvt*) context);
    uint32_t count = ctx->passwordCount;

    List* users = NULL;

    for (uint32_t i = 0; i < count; i++ )
    {
        users = List_addString(users, String_clone(ctx->passwords[i].user, alloc), alloc);
    }

    return users;
}
int main()
{
    char* pingBenc = "d1:q4:ping4:txid4:abcde";
    struct Allocator* alloc = MallocAllocator_new(1<<22);
    struct TestFramework* tf = TestFramework_setUp("0123456789abcdefghijklmnopqrstuv", alloc, NULL);
    struct Ducttape_pvt* dt = Identity_cast((struct Ducttape_pvt*) tf->ducttape);

    struct Allocator* allocator = MallocAllocator_new(85000);
    uint16_t buffLen = sizeof(struct Ducttape_IncomingForMe) + 8 + strlen(pingBenc);
    uint8_t* buff = allocator->calloc(buffLen, 1, allocator);
    struct Headers_SwitchHeader* sh = (struct Headers_SwitchHeader*) buff;
    sh->label_be = Endian_hostToBigEndian64(4);
    struct Headers_IP6Header* ip6 = (struct Headers_IP6Header*) &sh[1];

    uint8_t herPublicKey[32];
    Base32_decode(herPublicKey, 32,
                  (uint8_t*) "0z5tscp8td1sc6cv4htp7jbls79ltqxw9pbg190x0kbm1lguqtx0", 52);
    AddressCalc_addressForPublicKey(ip6->sourceAddr, herPublicKey);

    struct Headers_UDPHeader* udp = (struct Headers_UDPHeader*) &ip6[1];
    ip6->hopLimit = 0;
    ip6->nextHeader = 17;
    udp->sourceAndDestPorts = 0;
    udp->length_be = Endian_hostToBigEndian16(strlen(pingBenc));

    strncpy((char*)(udp + 1), pingBenc, strlen(pingBenc));

    dt->switchInterface.receiveMessage = catchResponse;
    dt->switchInterface.receiverContext = NULL;

    // bad checksum
    udp->checksum_be = 1;
    struct Message m = { .bytes = buff, .length = buffLen, .padding = 0 };
    Ducttape_injectIncomingForMe(&m, &dt->public, herPublicKey);
    Assert_always(!dt->switchInterface.receiverContext);

    // zero checksum
    udp->checksum_be = 0;
    struct Message m2 = { .bytes = buff, .length = buffLen, .padding = 0 };
    Ducttape_injectIncomingForMe(&m2, &dt->public, herPublicKey);
    Assert_always(dt->switchInterface.receiverContext);

    // good checksum
    udp->checksum_be =
        Checksum_udpIp6(ip6->sourceAddr, (uint8_t*) udp, strlen(pingBenc) + Headers_UDPHeader_SIZE);
    struct Message m3 = { .bytes = buff, .length = buffLen, .padding = 0 };
    Ducttape_injectIncomingForMe(&m3, &dt->public, herPublicKey);
    Assert_always(dt->switchInterface.receiverContext);
}
Esempio n. 30
0
static void traceStep(struct RouteTracer_Trace* trace, struct Node* next)
{
    struct RouteTracer_pvt* ctx = Identity_cast((struct RouteTracer_pvt*)trace->tracer);

    if (!next) {
        // can't find a next node, stalled.
        Timeout_setTimeout(noPeers, trace, 0, trace->tracer->eventBase, trace->pub.alloc);
        return;
    }

    Assert_true(LabelSplicer_routesThrough(trace->target, next->address.path));

    trace->lastNodeAsked = next->address.path;

    struct RouterModule_Promise* rp =
        RouterModule_newMessage(next, 0, ctx->router, trace->pub.alloc);

    Dict* message = Dict_new(rp->alloc);

    #ifdef Version_4_COMPAT
        if (next->version < 5) {
            // The node doesn't support the new API so try running a search for
            // the bitwise complement of their address to get some peers.
            Dict_putString(message, CJDHTConstants_QUERY, CJDHTConstants_QUERY_FN, rp->alloc);
            String* notAddr = String_newBinary((char*)next->address.ip6.bytes, 16, rp->alloc);
            for (int i = 0; i < 16; i++) {
                notAddr->bytes[i] ^= 0xff;
            }
            Dict_putString(message, CJDHTConstants_TARGET, notAddr, rp->alloc);
            log(ctx->logger, trace, "Sending legacy search method because getpeers is unavailable");
        } else {
    #endif

    Dict_putString(message, CJDHTConstants_QUERY, CJDHTConstants_QUERY_GP, rp->alloc);
    uint64_t labelForThem = LabelSplicer_unsplice(trace->target, next->address.path);
    labelForThem = Endian_hostToBigEndian64(labelForThem);
    String* target = String_newBinary((char*)&labelForThem, 8, rp->alloc);
    Dict_putString(message, CJDHTConstants_TARGET, target, rp->alloc);
    log(ctx->logger, trace, "Sending getpeers request");

    #ifdef Version_4_COMPAT
        }
    #endif

    rp->userData = trace;
    rp->callback = responseCallback;

    RouterModule_sendMessage(rp, message);
}