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; }
// // 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; }
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; }