bool
ccnxCodecSchemaV1FixedHeaderDecoder_Decode(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary)
{
    if (ccnxCodecTlvDecoder_EnsureRemaining(decoder, _fixedHeaderBytes)) {
        PARCBuffer *buffer = ccnxCodecTlvDecoder_GetValue(decoder, _fixedHeaderBytes);
        bool success = ccnxTlvDictionary_PutBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader, buffer);

        // validation
        parcBuffer_SetPosition(buffer, _fixedHeader_VersionOffset);
        uint8_t version = parcBuffer_GetUint8(buffer);

        parcBuffer_SetPosition(buffer, _fixedHeader_PacketLengthOffset);
        uint16_t packetLength = parcBuffer_GetUint16(buffer);

        parcBuffer_SetPosition(buffer, _fixedHeader_HopLimitOffset);
        uint8_t hopLimit = parcBuffer_GetUint8(buffer);

        parcBuffer_SetPosition(buffer, _fixedHeader_HeaderLengthOffset);
        uint8_t headerLength = parcBuffer_GetUint8(buffer);

        if (version != 1) {
            CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_VERSION, __func__, __LINE__, _fixedHeader_VersionOffset);
            ccnxCodecTlvDecoder_SetError(decoder, error);
            ccnxCodecError_Release(&error);
            success = false;
        } else if (packetLength < _fixedHeaderBytes) {
            CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_PACKETLENGTH_TOO_SHORT, __func__, __LINE__, _fixedHeader_PacketTypeOffset);
            ccnxCodecTlvDecoder_SetError(decoder, error);
            ccnxCodecError_Release(&error);
            success = false;
        } else if (headerLength < _fixedHeaderBytes) {
            CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_HEADERLENGTH_TOO_SHORT, __func__, __LINE__, _fixedHeader_HeaderLengthOffset);
            ccnxCodecTlvDecoder_SetError(decoder, error);
            ccnxCodecError_Release(&error);
            success = false;
        } else if (packetLength < headerLength) {
            CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_PACKETLENGTHSHORTER, __func__, __LINE__, _fixedHeader_PacketTypeOffset);
            ccnxCodecTlvDecoder_SetError(decoder, error);
            ccnxCodecError_Release(&error);
            success = false;
        }

        // decoder now points to just past the fixed header
        parcBuffer_Release(&buffer);

        // Set the hoplimit in the dictionary.
        ccnxTlvDictionary_PutInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_HOPLIMIT, hopLimit);

        return success;
    } else {
        CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_DECODE, __func__, __LINE__, ccnxCodecTlvDecoder_Position(decoder));
        ccnxCodecTlvDecoder_SetError(decoder, error);
        ccnxCodecError_Release(&error);
        return false;
    }
}
//
// Receive a message from the specified link.
//
static CCNxMetaMessage *
_ETHReceiveMessage(AthenaTransportLink *athenaTransportLink, struct ether_addr *peerAddress, socklen_t *peerAddressLength)
{
    struct _ETHLinkData *linkData = athenaTransportLink_GetPrivateData(athenaTransportLink);
    CCNxMetaMessage *ccnxMetaMessage = NULL;
    AthenaTransportLinkEvent events = 0;

    PARCBuffer *message = athenaEthernet_Receive(linkData->athenaEthernet, -1, &events);
    if (message == NULL) {
        return NULL;
    }
    // Mark any pending events
    if (events) {
        athenaTransportLink_SetEvent(athenaTransportLink, events);
    }

    // Map the header
    struct ether_header *header = parcBuffer_Overlay(message, sizeof(struct ether_header));

    // If the destination does not match my address, drop the message
    if (memcmp(&linkData->link.myAddress, header->ether_dhost, ETHER_ADDR_LEN * sizeof(uint8_t)) != 0) {
        linkData->_stats.receive_NoLinkDestination++;
        parcBuffer_Release(&message);
        return NULL;
    }
    assertTrue(header->ether_type == htons(CCNX_ETHERTYPE), "Unexpected ether type %x", header->ether_type);

    // Set peerAddress from header source address
    *peerAddressLength = ETHER_ADDR_LEN * sizeof(uint8_t);
    memcpy(peerAddress, header->ether_shost, *peerAddressLength);

    parcBuffer_SetPosition(message, sizeof(struct ether_header));
    PARCBuffer *wireFormatBuffer = parcBuffer_Slice(message);
    parcBuffer_Release(&message);
    parcBuffer_SetPosition(wireFormatBuffer, 0);

    // Construct, and return a ccnxMetaMessage from the wire format buffer.
    ccnxMetaMessage = ccnxMetaMessage_CreateFromWireFormatBuffer(wireFormatBuffer);
    if (ccnxMetaMessage == NULL) {
        linkData->_stats.receive_DecodeFailed++;
        parcLog_Error(athenaTransportLink_GetLogger(athenaTransportLink), "Failed to decode message from received packet.");
    } else if (ccnxTlvDictionary_GetSchemaVersion(ccnxMetaMessage) == CCNxTlvDictionary_SchemaVersion_V0) {
        parcLog_Debug(athenaTransportLink_GetLogger(athenaTransportLink),
                      "received deprecated version %d message\n", ccnxTlvDictionary_GetSchemaVersion(ccnxMetaMessage));
    }
    parcBuffer_Release(&wireFormatBuffer);

    return ccnxMetaMessage;
}
Beispiel #3
0
/**
 * 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;
}
CCNxNameSegment *
ccnxNameSegment_ParseURISegment(const PARCURISegment *uriSegment)
{
    CCNxNameSegment *result = NULL;

    PARCBuffer *buffer = parcURISegment_GetBuffer(uriSegment);

    size_t originalPosition = parcBuffer_Position(buffer);
    CCNxNameLabel *label = ccnxNameLabel_Parse(buffer);

    if (ccnxNameLabel_IsValid(label)) {
        PARCBuffer *value = parcBuffer_Slice(buffer);

        CCNxNameLabelType nameType = ccnxNameLabel_GetType(label);
        if (nameType != CCNxNameLabelType_Unknown) {
            result = ccnxNameSegment_CreateLabelValue(label, value);
        }

        ccnxNameLabel_Release(&label);
        parcBuffer_Release(&value);

        parcBuffer_SetPosition(buffer, originalPosition);
    }

    return result;
}
Beispiel #5
0
void
parcJSONParser_Advance(PARCJSONParser *parser, long bytes)
{
    parcJSONParser_OptionalAssertValid(parser);

    parcBuffer_SetPosition(parser->buffer, parcBuffer_Position(parser->buffer) + bytes);
}
CCNxCodecNetworkBufferIoVec *
athenaTransportLinkModule_GetMessageIoVector(CCNxMetaMessage *message)
{
    CCNxCodecNetworkBufferIoVec *iovec = ccnxWireFormatMessage_GetIoVec(message);

    // If there was no io vector present, check for a buffer and convert that into an iovec
    if (iovec == NULL) {
        PARCBuffer *buffer = ccnxWireFormatMessage_GetWireFormatBuffer(message);
        if (buffer == NULL) { // if there's no iovec or buffer, encode the message and return the iovec
            athena_EncodeMessage(message);
            iovec = ccnxWireFormatMessage_GetIoVec(message);
            iovec = ccnxCodecNetworkBufferIoVec_Acquire(iovec);
        } else {
            CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_Create(&ParcMemoryMemoryBlock, NULL);
            assertNotNull(netbuff, "Null network buffer allocation");
            parcBuffer_SetPosition(buffer, 0);
            ccnxCodecNetworkBuffer_PutBuffer(netbuff, buffer);
            iovec = ccnxCodecNetworkBuffer_CreateIoVec(netbuff);
            ccnxCodecNetworkBuffer_Release(&netbuff);
        }
    } else {
        iovec = ccnxCodecNetworkBufferIoVec_Acquire(iovec);
    }

    return iovec;
}
Beispiel #7
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;
}
PARCBuffer *
ccnxInterestPayloadId_GetValue(const CCNxInterestPayloadId *id)
{
    PARCBuffer *data = ccnxNameSegment_GetValue(id->nameSegment);
    parcBuffer_Rewind(data);
    parcBuffer_SetPosition(data, 1);
    return data;
}
Beispiel #9
0
PARCBuffer *
parcBuffer_Clear(PARCBuffer *buffer)
{
    parcBuffer_SetPosition(buffer, 0);
    parcBuffer_SetLimit(buffer, parcBuffer_Capacity(buffer));
    _discardMark(buffer);
    return buffer;
}
Beispiel #10
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);
}
Beispiel #11
0
PARCBuffer *
parcBuffer_PutArray(PARCBuffer *buffer, size_t arrayLength, const uint8_t array[arrayLength])
{
    parcBuffer_OptionalAssertValid(buffer);
    assertTrue(parcBuffer_Remaining(buffer) >= arrayLength,
               "Buffer overflow");

    parcByteArray_PutBytes(buffer->array, _effectivePosition(buffer), arrayLength, array);
    return parcBuffer_SetPosition(buffer, parcBuffer_Position(buffer) + arrayLength);
}
Beispiel #12
0
PARCBuffer *
parcBuffer_AllocateCString(const char *string)
{
    size_t length = strlen(string);
    PARCBuffer *buffer = parcBuffer_Allocate(length + 1);
    parcBuffer_PutArray(buffer, length, (const uint8_t *) string);
    parcBuffer_PutUint8(buffer, 0);
    parcBuffer_SetPosition(buffer, buffer->position - 1);
    parcBuffer_Flip(buffer);

    return buffer;
}
Beispiel #13
0
bool
parcBuffer_SkipOver(PARCBuffer *buffer, size_t length, const uint8_t bytesToSkipOver[length])
{
    while (parcBuffer_Remaining(buffer) > 0) {
        uint8_t character = parcBuffer_GetUint8(buffer);
        if (memchr(bytesToSkipOver, character, length) == NULL) {
            parcBuffer_SetPosition(buffer, parcBuffer_Position(buffer) - 1);
            return true;
        }
    }
    return false;
}
int
ccnxCodecSchemaV1FixedHeaderDecoder_GetFlags(CCNxTlvDictionary *packetDictionary)
{
    PARCBuffer *fixedHeader = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader);
    if (fixedHeader != NULL) {
        parcBuffer_SetPosition(fixedHeader, _fixedHeader_FlagsOffset);
        uint8_t flags = parcBuffer_GetUint8(fixedHeader);
        return flags;
    }

    return -1;
}
int
ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketLength(CCNxTlvDictionary *packetDictionary)
{
    PARCBuffer *fixedHeader = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader);
    if (fixedHeader != NULL) {
        parcBuffer_SetPosition(fixedHeader, _fixedHeader_PacketLengthOffset);
        uint16_t payloadLength = parcBuffer_GetUint16(fixedHeader);
        return payloadLength;
    }

    return -1;
}
Beispiel #16
0
PARCBuffer *
parcBuffer_PutBuffer(PARCBuffer *result, const PARCBuffer *buffer)
{
    parcBuffer_OptionalAssertValid(buffer);
    assertTrue(parcBuffer_Remaining(result) >= parcBuffer_Remaining(buffer),
               "Buffer overflow. %zd bytes remaining, %zd required.", parcBuffer_Remaining(result), parcBuffer_Remaining(buffer));

    size_t length = parcBuffer_Remaining(buffer);
    parcByteArray_ArrayCopy(result->array, _effectivePosition(result), buffer->array, _effectivePosition(buffer), length);
    parcBuffer_SetPosition(result, parcBuffer_Position(result) + length);
    return result;
}
Beispiel #17
0
static void *
_ccnxChunker_NextFromBuffer(PARCBufferChunker *chunker, _ChunkerState *state)
{
    size_t chunkSize = state->nextChunkSize;

    parcBuffer_SetPosition(chunker->data, state->position);
    PARCBuffer *slice = parcBuffer_CreateFromArray(parcBuffer_Overlay(chunker->data, chunkSize), chunkSize);
    slice = parcBuffer_Flip(slice);

    _advanceState(chunker, state);

    return slice;
}
Beispiel #18
0
bool
parcBuffer_SkipTo(PARCBuffer *buffer, size_t length, const uint8_t bytesToSkipTo[length])
{
    bool result = false;

    while (parcBuffer_Remaining(buffer) > 0) {
        uint8_t character = parcBuffer_GetUint8(buffer);
        if (memchr(bytesToSkipTo, character, length) != NULL) {
            parcBuffer_SetPosition(buffer, parcBuffer_Position(buffer) - 1);
            result = true;
            break;
        }
    }
    return result;
}
int
ccnxCodecSchemaV1FixedHeaderDecoder_GetHeaderLength(CCNxTlvDictionary *packetDictionary)
{
    int length = -1;
    PARCBuffer *fixedHeader = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader);
    if (fixedHeader != NULL) {
        parcBuffer_SetPosition(fixedHeader, _fixedHeader_HeaderLengthOffset);
        uint8_t headerLength = parcBuffer_GetUint8(fixedHeader);

        // 8 is the minimum size of headerLength
        if (headerLength >= _fixedHeaderBytes) {
            length = headerLength;
        }
    }

    return length;
}
Beispiel #20
0
uint64_t
parcBuffer_ParseDecimalNumber(PARCBuffer *buffer)
{
    char *bytes = parcBuffer_Overlay(buffer, 0);

    int start = 0;

    unsigned count = 0;
    uint64_t result = 0;
    for (int i = start; i < parcBuffer_Remaining(buffer) && isdigit(bytes[i]); i++) {
        result = (result * 10) + _digittoint(bytes[i]);
        count++;
    }

    parcBuffer_SetPosition(buffer, parcBuffer_Position(buffer) + count);

    return result;
}
Beispiel #21
0
static char *
_toString(const PARCLogEntry *entry)
{
    PARCBufferComposer *composer = parcBufferComposer_Create();

    parcBufferComposer_Format(composer, "%ld.%06d %d ",
                              (long) entry->timeStamp.tv_sec, (int) entry->timeStamp.tv_usec, entry->level);

    size_t position = parcBuffer_Position(entry->payload);
    parcBufferComposer_PutBuffer(composer, entry->payload);
    parcBuffer_SetPosition(entry->payload, position);

    PARCBuffer *buffer = parcBufferComposer_GetBuffer(composer);
    parcBuffer_Rewind(buffer);

    char *result = parcBuffer_ToString(buffer);
    parcBufferComposer_Release(&composer);

    return result;
}
Beispiel #22
0
uint64_t
parcBuffer_ParseHexNumber(PARCBuffer *buffer)
{
    char *bytes = parcBuffer_Overlay(buffer, 0);

    int start = 0;
    if (parcBuffer_Remaining(buffer) > 2) {
        if (bytes[0] == '0' && bytes[1] == 'x') {
            start = 2;
        }
    }

    unsigned count = 0;
    uint64_t result = 0;
    for (int i = start; i < parcBuffer_Remaining(buffer) && isxdigit(bytes[i]); i++) {
        result = (result * 16) + _digittoint(bytes[i]);
        count++;
    }

    parcBuffer_SetPosition(buffer, parcBuffer_Position(buffer) + start + count);

    return result;
}
Beispiel #23
0
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;
}
//
// Receive a message from the specified link.
//
static CCNxMetaMessage *
_UDPReceiveMessage(AthenaTransportLink *athenaTransportLink, struct sockaddr_in *peerAddress, socklen_t *peerAddressLength)
{
    struct _UDPLinkData *linkData = athenaTransportLink_GetPrivateData(athenaTransportLink);
    CCNxMetaMessage *ccnxMetaMessage = NULL;
    size_t messageLength;

    // If an MTU has been set, allocate a buffer of that size to avoid having to peek at the message,
    // othersize derive the link from the header and allocate a buffer based on the message size.

    if ((messageLength = linkData->link.mtu) == 0) {
        messageLength = _messageLengthFromHeader(athenaTransportLink, linkData);
        if (messageLength <= 0) {
            return NULL;
        }
    }

    PARCBuffer *wireFormatBuffer = parcBuffer_Allocate(messageLength);

    char *buffer = parcBuffer_Overlay(wireFormatBuffer, 0);
    *peerAddressLength = (socklen_t) sizeof(struct sockaddr_in);
    ssize_t readCount = recvfrom(linkData->fd, buffer, messageLength, 0, (struct sockaddr *) peerAddress, peerAddressLength);

    // On error, just return and retry.
    if (readCount == -1) {
        linkData->_stats.receive_ReadError++;
        parcLog_Debug(athenaTransportLink_GetLogger(athenaTransportLink), "read error (%s)", strerror(errno));
        parcBuffer_Release(&wireFormatBuffer);
        return NULL;
    }

    // A zero read means either no more data is currently available or our peer hungup.
    // Just return to retry as we'll detect EOF when we come back at the top of UDPReceive
    if (readCount == 0) {
        parcBuffer_Release(&wireFormatBuffer);
        return NULL;
    }

    // If it was it a short read just return to retry later.
    while (readCount < messageLength) {
        linkData->_stats.receive_ShortRead++;
        parcLog_Debug(athenaTransportLink_GetLogger(athenaTransportLink), "short read error (%s)", strerror(errno));
        parcBuffer_Release(&wireFormatBuffer);
        return NULL;
    }

    parcLog_Debug(athenaTransportLink_GetLogger(athenaTransportLink), "received message (size=%d)", readCount);
    parcBuffer_SetPosition(wireFormatBuffer, parcBuffer_Position(wireFormatBuffer) + readCount);
    parcBuffer_Flip(wireFormatBuffer);

    // Construct, and return a ccnxMetaMessage from the wire format buffer.
    ccnxMetaMessage = ccnxMetaMessage_CreateFromWireFormatBuffer(wireFormatBuffer);
    if (ccnxTlvDictionary_GetSchemaVersion(ccnxMetaMessage) == CCNxTlvDictionary_SchemaVersion_V0) {
        parcLog_Debug(athenaTransportLink_GetLogger(athenaTransportLink),
                      "received deprecated version %d message\n", ccnxTlvDictionary_GetSchemaVersion(ccnxMetaMessage));
    }
    if (ccnxMetaMessage == NULL) {
        linkData->_stats.receive_DecodeFailed++;
        parcLog_Error(athenaTransportLink_GetLogger(athenaTransportLink), "Failed to decode message from received packet.");
    }
    parcBuffer_Release(&wireFormatBuffer);

    return ccnxMetaMessage;
}
Beispiel #25
0
/**
 * 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;
}
static int
_UDPSend(AthenaTransportLink *athenaTransportLink, CCNxMetaMessage *ccnxMetaMessage)
{
    struct _UDPLinkData *linkData = athenaTransportLink_GetPrivateData(athenaTransportLink);

    if (ccnxTlvDictionary_GetSchemaVersion(ccnxMetaMessage) == CCNxTlvDictionary_SchemaVersion_V0) {
        parcLog_Debug(athenaTransportLink_GetLogger(athenaTransportLink),
                      "sending deprecated version %d message\n", ccnxTlvDictionary_GetSchemaVersion(ccnxMetaMessage));
    }

    // Get a wire format buffer and write it out.
    PARCBuffer *wireFormatBuffer = athenaTransportLinkModule_GetMessageBuffer(ccnxMetaMessage);

    parcBuffer_SetPosition(wireFormatBuffer, 0);
    size_t length = parcBuffer_Limit(wireFormatBuffer);
    char *buffer = parcBuffer_Overlay(wireFormatBuffer, length);

    if (linkData->link.mtu) {
        if (length > linkData->link.mtu) {
            errno = EMSGSIZE;
            parcBuffer_Release(&wireFormatBuffer);
            return -1;
        }
    }

    parcLog_Debug(athenaTransportLink_GetLogger(athenaTransportLink),
                  "sending message (size=%d)", length);

    ssize_t writeCount = 0;
#ifdef LINUX_IGNORESIGPIPE
    writeCount = sendto(linkData->fd, buffer, length, MSG_NOSIGNAL,
                        (struct sockaddr *) &linkData->link.peerAddress, linkData->link.peerAddressLength);
#else
    writeCount = sendto(linkData->fd, buffer, length, 0,
                        (struct sockaddr *) &linkData->link.peerAddress, linkData->link.peerAddressLength);
#endif

    // on error close the link, else return to retry a zero write
    if (writeCount == -1) {
        if ((errno == EAGAIN) || (errno == EINTR)) {
            linkData->_stats.send_SendRetry++;
            parcLog_Debug(athenaTransportLink_GetLogger(athenaTransportLink), "send retry (%s)", strerror(errno));
        } else {
            athenaTransportLink_SetEvent(athenaTransportLink, AthenaTransportLinkEvent_Error);
            parcLog_Error(athenaTransportLink_GetLogger(athenaTransportLink),
                          "send error (%s)", strerror(errno));
        }
        parcBuffer_Release(&wireFormatBuffer);
        return -1;
    }

    // Short write
    if (writeCount != length) {
        linkData->_stats.send_ShortWrite++;
        parcLog_Debug(athenaTransportLink_GetLogger(athenaTransportLink), "short write");
        parcBuffer_Release(&wireFormatBuffer);
        return -1;
    }

    parcBuffer_Release(&wireFormatBuffer);
    return 0;
}