/**
 * Given a CCNxName, a directory path, and a requested chunk number, create a directory listing and return the specified
 * chunk of the directory listing as the payload of a newly created CCNxContentObject.
 * The new CCnxContentObject must eventually be released by calling ccnxContentObject_Release().
 *
 * @param [in] name The CCNxName to use when creating the new CCNxContentObject.
 * @param [in] directoryPath The directory whose contents are being listed.
 * @param [in] requestedChunkNumber The number of the requested chunk from the complete directory listing.
 *
 * @return A new CCNxContentObject instance containing the request chunk of the directory listing.
 */
static CCNxContentObject *
_createListResponse(CCNxName *name, const char *directoryPath, uint64_t requestedChunkNumber)
{
    CCNxContentObject *result = NULL;

    PARCBuffer *directoryList = tutorialFileIO_CreateDirectoryListing(directoryPath);

    uint64_t totalChunksInDirList = _getNumberOfChunksRequired(parcBuffer_Limit(directoryList), tutorialCommon_ChunkSize);
    if (requestedChunkNumber < totalChunksInDirList) {
        // Set the buffer's position to the start of the desired chunk.
        parcBuffer_SetPosition(directoryList, (requestedChunkNumber * tutorialCommon_ChunkSize));

        // See if we have more than 1 chunk's worth of data to in the buffer. If so, set the buffer's limit
        // to the end of the chunk.
        size_t chunkLen = parcBuffer_Remaining(directoryList);

        if (chunkLen > tutorialCommon_ChunkSize) {
            parcBuffer_SetLimit(directoryList, parcBuffer_Position(directoryList) + tutorialCommon_ChunkSize);
        }

        printf("tutorialServer: Responding to 'list' command with chunk %ld/%ld\n", (unsigned long) requestedChunkNumber, (unsigned long) totalChunksInDirList);

        // Calculate the final chunk number
        uint64_t finalChunkNumber = (totalChunksInDirList > 0) ? totalChunksInDirList - 1 : 0; // the final chunk, 0-based

        // At this point, dirListBuf has its position and limit set to the beginning and end of the
        // specified chunk.
        result = _createContentObject(name, directoryList, finalChunkNumber);
    }

    parcBuffer_Release(&directoryList);

    return result;
}
Exemple #2
0
PARCBuffer *
athenaEthernet_Receive(AthenaEthernet *athenaEthernet, int timeout, AthenaTransportLinkEvent *events)
{
    // Allocate, and read, a new BPF buffer if no packets are currently pending in an old one
    if (athenaEthernet->bpfBuffer == NULL) {
        athenaEthernet->bpfBuffer = parcBuffer_Allocate(athenaEthernet->etherBufferLength);
        uint8_t *buffer = parcBuffer_Overlay(athenaEthernet->bpfBuffer, 0);

        athenaEthernet->readCount = read(athenaEthernet->fd, buffer, athenaEthernet->etherBufferLength);
        if (athenaEthernet->readCount == -1) {
            if ((errno == EAGAIN) || (errno == EINTR)) {
                parcLog_Info(athenaEthernet->log, "Ethernet read retry");
                return NULL;
            }
            parcLog_Error(athenaEthernet->log, "recv: %s", strerror(errno));
            *events = AthenaTransportLinkEvent_Error;
            parcBuffer_Release(&athenaEthernet->bpfBuffer);
            return NULL;
        }
        parcLog_Debug(athenaEthernet->log, "received bpf packet (size=%d)", athenaEthernet->readCount);
    }

    // Obtain the current position in the BPF buffer to return a message from
    size_t position = parcBuffer_Position(athenaEthernet->bpfBuffer);

    // Read the BPF header and seek past it
    struct bpf_hdr *bpfhdr = parcBuffer_Overlay(athenaEthernet->bpfBuffer, sizeof(struct bpf_hdr));
    parcBuffer_SetLimit(athenaEthernet->bpfBuffer, position + bpfhdr->bh_hdrlen + bpfhdr->bh_datalen);
    parcBuffer_SetPosition(athenaEthernet->bpfBuffer, position + bpfhdr->bh_hdrlen);
    parcLog_Debug(athenaEthernet->log, "received message (size=%d)", bpfhdr->bh_datalen);

    // Slice a new PARCBuffer with the message to send up.
    PARCBuffer *wireFormatBuffer = parcBuffer_Slice(athenaEthernet->bpfBuffer);

    // If there's another packet in the buffer, position it and flag a receive event
    if ((athenaEthernet->readCount - (position + bpfhdr->bh_hdrlen + bpfhdr->bh_datalen)) != 0) {
        parcBuffer_SetLimit(athenaEthernet->bpfBuffer, athenaEthernet->readCount);
        parcBuffer_SetPosition(athenaEthernet->bpfBuffer,
                               BPF_WORDALIGN(position + bpfhdr->bh_hdrlen + bpfhdr->bh_datalen));
        // Mark a receive event for this packet
        *events = AthenaTransportLinkEvent_Receive;
    } else {
        parcBuffer_Release(&athenaEthernet->bpfBuffer);
    }

    return wireFormatBuffer;
}
Exemple #3
0
PARCBuffer *
parcBuffer_Clear(PARCBuffer *buffer)
{
    parcBuffer_SetPosition(buffer, 0);
    parcBuffer_SetLimit(buffer, parcBuffer_Capacity(buffer));
    _discardMark(buffer);
    return buffer;
}
Exemple #4
0
LONGBOW_TEST_CASE(Global, parcNetwork_LinkAddress_Parse_dots)
{
    char *expected = "link://0123.4567.89ab";
    PARCBuffer *address = parcNetwork_ParseLinkAddress(expected);

    PARCBuffer *e = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6);

    parcBuffer_SetPosition(address, 0);
    parcBuffer_SetPosition(e, 0);
    parcBuffer_SetLimit(address, 6);
    parcBuffer_SetLimit(e, 6);

    assertTrue(parcBuffer_Equals(address, e),
               "Expected result failed.");

    parcBuffer_Release(&e);
    parcBuffer_Release(&address);
}
PARCBuffer *
tutorialFileIO_GetFileChunk(const char *fileName, size_t chunkSize, uint64_t chunkNum)
{
    FILE *file = fopen(fileName, "r");

    assertNotNull(file, "Could not open file '%s' - stopping.", fileName);

    // When PARCFileInputStream has a Seek() function, consider using it instead of
    // the following approach.

    // Seek to the location of the desired chunk in the file.
    assertTrue(fseek(file, chunkSize * chunkNum, SEEK_SET) == 0, "Could not seek to desired chunk");

    // If we're here, we were able to seek to the start of the desired chunk

    PARCBuffer *result = parcBuffer_Allocate(chunkSize);

    size_t numberOfBytesNeeded = chunkSize;
    size_t numberOfBytesRead = 0;       // # bytes read in each read.
    size_t totalNumberOfBytesRead = 0;  // Overall # of bytes read

    // Read until we get the required number of bytes.
    while (numberOfBytesNeeded > 0
           && (numberOfBytesRead = fread(parcBuffer_Overlay(result, 0), 1, numberOfBytesNeeded, file)) > 0) {
        numberOfBytesNeeded -= numberOfBytesRead;
        parcBuffer_SetPosition(result, parcBuffer_Position(result) + numberOfBytesRead);

        totalNumberOfBytesRead += numberOfBytesRead;
    }

    parcBuffer_SetLimit(result, totalNumberOfBytesRead);
    parcBuffer_Flip(result);

    fclose(file);

    return result;
}
/**
 * Run the consumer to fetch the specified file. Save it to disk once transferred.
 *
 * @param [in] target Name of the content to request.
 * @param [in] outFile Name of the file to which the buffer will be written.
 */
static int
_ccnxFileRepoClient_Run(char *target, char *outFile)
{
    parcSecurity_Init();

    PARCLog *log = _ccnxFileRepoClient_CreateLogger();

    CCNxPortalFactory *factory = _setupConsumerPortalFactory();
    CCNxPortal *portal = ccnxPortalFactory_CreatePortal(factory, ccnxPortalRTA_Message);
    assertNotNull(portal, "Expected a non-null CCNxPortal pointer.");

    CCNxName *name = ccnxName_CreateFromCString(target);
    CCNxInterest *interest = ccnxInterest_CreateSimple(name);
    CCNxMetaMessage *message = ccnxMetaMessage_CreateFromInterest(interest);

    if (ccnxPortal_Send(portal, message, CCNxStackTimeout_Never)) {
        while (ccnxPortal_IsError(portal) == false) {
            CCNxMetaMessage *response = ccnxPortal_Receive(portal, CCNxStackTimeout_Never);
            if (response != NULL) {
                if (ccnxMetaMessage_IsManifest(response)) {
                    parcLog_Info(log, "Received root manifest. Beginning to retrieve the content.");

                    // Extract the manifest and instantiate a new fetcher for it
                    CCNxManifest *root = ccnxMetaMessage_GetManifest(response);
                    CCNxFileRepoManifestFetcher *fetcher = ccnxFileRepoManifestFetcher_Create(portal, root);

                    // Initialize the file offset and I/O buffer
                    size_t fileOffset = 0;
                    PARCBuffer *chunkBuffer = parcBuffer_Allocate(ccnxFileRepoCommon_ClientBufferSize);

                    // Start reading from the manifest until done
                    bool done = false;
                    while (!done) {
                        // Reset the buffer information
                        parcBuffer_SetPosition(chunkBuffer, 0);
                        parcBuffer_SetLimit(chunkBuffer, ccnxFileRepoCommon_ClientBufferSize);

                        // Fill the buffer with data from the manifest
                        done = ccnxFileRepoManifestFetcher_FillBuffer(fetcher, chunkBuffer);
                        parcBuffer_Flip(chunkBuffer);

                        // Write the buffer to the file
                        size_t totalSize = parcBuffer_Remaining(chunkBuffer);
                        _ccnxFileRepoClient_AppendBufferToFile(outFile, chunkBuffer, fileOffset);
                        fileOffset += totalSize;

                        // Flip the buffer back around for writing
                        parcBuffer_Flip(chunkBuffer);
                    }
                    parcBuffer_Release(&chunkBuffer);

                    break;
                } else if (ccnxMetaMessage_IsContentObject(response)) {
                    parcLog_Info(log, "Received a content object. Dump the payload and exit.");
                    CCNxContentObject *contentObject = ccnxMetaMessage_GetContentObject(response);
                    PARCBuffer *payload = ccnxContentObject_GetPayload(contentObject);
                    _ccnxFileRepoClient_AppendBufferToFile(outFile, payload, 0);
                    break;
                }
            }
            ccnxMetaMessage_Release(&response);
        }
    }

    ccnxPortal_Release(&portal);
    ccnxPortalFactory_Release(&factory);

    parcSecurity_Fini();
    return 0;
}