/** * 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; }
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 * parcBuffer_Clear(PARCBuffer *buffer) { parcBuffer_SetPosition(buffer, 0); parcBuffer_SetLimit(buffer, parcBuffer_Capacity(buffer)); _discardMark(buffer); return buffer; }
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; }