void athena_ProcessMessage(Athena *athena, CCNxMetaMessage *ccnxMessage, PARCBitVector *ingressVector) { if (ccnxMetaMessage_IsInterest(ccnxMessage)) { const char *name = ccnxName_ToString(ccnxInterest_GetName(ccnxMessage)); parcLog_Debug(athena->log, "Processing Interest Message: %s", name); parcMemory_Deallocate(&name); CCNxInterest *interest = ccnxMetaMessage_GetInterest(ccnxMessage); _processInterest(athena, interest, ingressVector); athena->stats.numProcessedInterests++; } else if (ccnxMetaMessage_IsContentObject(ccnxMessage)) { const char *name = ccnxName_ToString(ccnxContentObject_GetName(ccnxMessage)); parcLog_Debug(athena->log, "Processing Content Object Message: %s", name); parcMemory_Deallocate(&name); CCNxContentObject *contentObject = ccnxMetaMessage_GetContentObject(ccnxMessage); _processContentObject(athena, contentObject, ingressVector); athena->stats.numProcessedContentObjects++; } else if (ccnxMetaMessage_IsControl(ccnxMessage)) { parcLog_Debug(athena->log, "Processing Control Message"); CCNxControl *control = ccnxMetaMessage_GetControl(ccnxMessage); _processControl(athena, control, ingressVector); athena->stats.numProcessedControlMessages++; } else if (ccnxMetaMessage_IsInterestReturn(ccnxMessage)) { parcLog_Debug(athena->log, "Processing Interest Return Message"); CCNxInterestReturn *interestReturn = ccnxMetaMessage_GetInterestReturn(ccnxMessage); _processInterestReturn(athena, interestReturn, ingressVector); athena->stats.numProcessedInterestReturns++; } else { trapUnexpectedState("Invalid CCNxMetaMessage type"); } }
// // Peek at the header and derive our total message length // static size_t _messageLengthFromHeader(AthenaTransportLink *athenaTransportLink, _UDPLinkData *linkData) { // Peek at our message header to determine the total length of buffer we need to allocate. size_t fixedHeaderLength = ccnxCodecTlvPacket_MinimalHeaderLength(); PARCBuffer *wireFormatBuffer = parcBuffer_Allocate(fixedHeaderLength); const uint8_t *peekBuffer = parcBuffer_Overlay(wireFormatBuffer, 0); ssize_t readCount = recv(linkData->fd, (void *) peekBuffer, fixedHeaderLength, MSG_PEEK); if (readCount == -1) { parcBuffer_Release(&wireFormatBuffer); if ((errno == EAGAIN) || (errno == EINTR)) { parcLog_Debug(athenaTransportLink_GetLogger(athenaTransportLink), "recv retry (%s)", strerror(errno)); linkData->_stats.receive_ReadRetry++; } else { linkData->_stats.receive_ReadError++; parcLog_Debug(athenaTransportLink_GetLogger(athenaTransportLink), "recv error (%s)", strerror(errno)); athenaTransportLink_SetEvent(athenaTransportLink, AthenaTransportLinkEvent_Error); } return -1; } // A zero read means no data if (readCount == 0) { parcBuffer_Release(&wireFormatBuffer); return -1; } // Check for a short header read, since we're only peeking here we just return and retry later if (readCount != fixedHeaderLength) { linkData->_stats.receive_ReadHeaderFailure++; parcBuffer_Release(&wireFormatBuffer); return -1; } // Obtain the total size of the message from the header size_t messageLength = ccnxCodecTlvPacket_GetPacketLength(wireFormatBuffer); parcBuffer_Release(&wireFormatBuffer); // Could do more to check the integrity of the message and framing. // If length is greater than our MTU we will find out in the read. if (messageLength < fixedHeaderLength) { linkData->_stats.receive_BadMessageLength++; parcLog_Error(athenaTransportLink_GetLogger(athenaTransportLink), "Framing error, flushing link."); char trash[MAXPATHLEN]; // Flush link to attempt to resync our framing while (read(linkData->fd, trash, sizeof(trash)) == sizeof(trash)) { parcLog_Error(athenaTransportLink_GetLogger(athenaTransportLink), "... flushing link."); } return -1; } return messageLength; }
/** * @abstract called from below the link adapter to coordinate termination of a link instance * @discussion * * This is called exclusively from the Transport Link Module to instigate the removal of * an active link. The link has been flagged closing by the originator. This method * must ensure that all references to the link have been removed and then call the * instance close method to finish the operation. * * @param [in] athenaTransportLinkAdapter link adapter instance * @param [in] athenaTransportLink link instance to remove * * Example: * @code * { * * } * @endcode */ static void _athenaTransportLinkAdapter_RemoveLink(AthenaTransportLinkAdapter *athenaTransportLinkAdapter, AthenaTransportLink *athenaTransportLink) { int linkId = -1; // if this is a listener it can simply be removed if (athenaTransportLink_IsNotRoutable(athenaTransportLink)) { if (athenaTransportLinkAdapter->listenerList) { for (int index = 0; index < parcArrayList_Size(athenaTransportLinkAdapter->listenerList); index++) { AthenaTransportLink *transportLink = parcArrayList_Get(athenaTransportLinkAdapter->listenerList, index); if (athenaTransportLink == transportLink) { parcArrayList_RemoveAtIndex(athenaTransportLinkAdapter->listenerList, index); _remove_from_pollfdList(athenaTransportLinkAdapter, athenaTransportLink); parcLog_Debug(athenaTransportLinkAdapter_GetLogger(athenaTransportLinkAdapter), "listener removed: %s", athenaTransportLink_GetName(athenaTransportLink)); athenaTransportLink_Release(&athenaTransportLink); return; } } } } // Remove from our internal instance list. // The index entry remains to be reused by links that are added in the future. if (athenaTransportLinkAdapter->instanceList) { for (int index = 0; index < parcArrayList_Size(athenaTransportLinkAdapter->instanceList); index++) { AthenaTransportLink *transportLink = parcArrayList_Get(athenaTransportLinkAdapter->instanceList, index); if (athenaTransportLink == transportLink) { parcArrayList_Set(athenaTransportLinkAdapter->instanceList, index, NULL); _remove_from_pollfdList(athenaTransportLinkAdapter, athenaTransportLink); linkId = index; break; } } } assertFalse(linkId == -1, "Attempt to remove link not found in link adapter lists"); // Callback to notify that the link has been removed and references need to be dropped. PARCBitVector *linkVector = parcBitVector_Create(); parcBitVector_Set(linkVector, linkId); athenaTransportLinkAdapter->removeLink(athenaTransportLinkAdapter->removeLinkContext, linkVector); parcBitVector_Release(&linkVector); // we assume all references to the linkId associated with this instance have been // cleared from the PIT and FIB when removeLink returns. parcLog_Debug(athenaTransportLinkAdapter_GetLogger(athenaTransportLinkAdapter), "link removed: %s", athenaTransportLink_GetName(athenaTransportLink)); athenaTransportLink_Release(&athenaTransportLink); }
static void _processContentObject(Athena *athena, CCNxContentObject *contentObject, PARCBitVector *ingressVector) { // // * (1) If it does not match anything in the PIT, drop it // PARCBitVector *egressVector = athenaPIT_Match(athena->athenaPIT, contentObject, ingressVector); if (egressVector) { if (parcBitVector_NumberOfBitsSet(egressVector) > 0) { // // * (2) Add to the Content Store // athenaContentStore_PutContentObject(athena->athenaContentStore, contentObject); // // * (3) Reverse path forward it via PIT entries // const char *egressVectorString = parcBitVector_ToString(egressVector); parcLog_Debug(athena->log, "Content Object forwarded to %s.", egressVectorString); parcMemory_Deallocate(&egressVectorString); PARCBitVector *result = athenaTransportLinkAdapter_Send(athena->athenaTransportLinkAdapter, contentObject, egressVector); if (result) { // if there are failed channels, client will resend interest unless we wish to retry here parcBitVector_Release(&result); } } parcBitVector_Release(&egressVector); } }
static CCNxMetaMessage * _PIT_Command(Athena *athena, CCNxInterest *interest) { CCNxMetaMessage *responseMessage; responseMessage = athenaPIT_ProcessMessage(athena->athenaPIT, interest); if (responseMessage) { return responseMessage; } CCNxName *ccnxName = ccnxInterest_GetName(interest); if (ccnxName_GetSegmentCount(ccnxName) > AthenaCommandSegment) { CCNxNameSegment *nameSegment = ccnxName_GetSegment(ccnxName, AthenaCommandSegment); char *command = ccnxNameSegment_ToString(nameSegment); if (strcasecmp(command, AthenaCommand_List) == 0) { parcLog_Debug(athena->log, "PIT List command invoked"); PARCList *pitEntries = athenaPIT_CreateEntryList(athena->athenaPIT); printf("\n"); for (size_t i = 0; i < parcList_Size(pitEntries); ++i) { PARCBuffer *strbuf = parcList_GetAtIndex(pitEntries, i); char *toprint = parcBuffer_ToString(strbuf); parcLog_Info(athena->log, "%s\n", toprint); parcMemory_Deallocate(&toprint); } parcList_Release(&pitEntries); responseMessage = _create_response(athena, ccnxName, "PIT listed on forwarder output log."); } else { responseMessage = _create_response(athena, ccnxName, "Unknown command: %s", command); } parcMemory_Deallocate(&command); } return responseMessage; }
static CCNxMetaMessage * _TemplateReceive(AthenaTransportLink *athenaTransportLink) { struct _TemplateLinkData *linkData = athenaTransportLink_GetPrivateData(athenaTransportLink); CCNxMetaMessage *ccnxMetaMessage = NULL; PARCBuffer *wireFormatBuffer = _internalRECEIVE(linkData); // On error, just return and retry. if (wireFormatBuffer == NULL) { parcLog_Debug(athenaTransportLink_GetLogger(athenaTransportLink), "read error (%s)", strerror(errno)); return NULL; } // 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."); } parcBuffer_Release(&wireFormatBuffer); if (parcDeque_Size(linkData->queue) > 0) { // if there's another message, mark an event. athenaTransportLink_SetEvent(athenaTransportLink, AthenaTransportLinkEvent_Receive); } return ccnxMetaMessage; }
LONGBOW_TEST_CASE(Global, parcLog_Debug) { PARCLog *log = (PARCLog *) longBowTestCase_GetClipBoardData(testCase); assertTrue(parcLog_Debug(log, "This is a debug message"), "Expected message to be logged successfully"); }
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; }
LONGBOW_TEST_CASE(Global, parcLog_Debug_WrongLevel) { PARCLog *log = (PARCLog *) longBowTestCase_GetClipBoardData(testCase); parcLog_SetLevel(log, PARCLogLevel_Off); assertFalse(parcLog_Debug(log, "This is a debug message"), "Expected message to not be logged"); }
ssize_t athenaEthernet_Send(AthenaEthernet *athenaEthernet, struct iovec *iov, int iovcnt) { ssize_t writeCount; writeCount = writev(athenaEthernet->fd, iov, iovcnt); parcLog_Debug(athenaEthernet->log, "sending message (size=%d)", writeCount); return writeCount; }
// // 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; }
static int _ETHSend(AthenaTransportLink *athenaTransportLink, CCNxMetaMessage *ccnxMetaMessage) { struct _ETHLinkData *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)); } // Construct our header to prepend struct ether_header header; memcpy(header.ether_shost, &(linkData->link.myAddress), ETHER_ADDR_LEN * sizeof(uint8_t)); memcpy(header.ether_dhost, &(linkData->link.peerAddress), ETHER_ADDR_LEN * sizeof(uint8_t)); header.ether_type = htons(athenaEthernet_GetEtherType(linkData->athenaEthernet)); // An iovec to contain the header and packet data struct iovec iov[2]; struct iovec *array = iov; int iovcnt = 2; size_t messageLength = 0; // If the iovec we're prepending to has more than one element, allocatedIovec holds the // allocated IO vector of the right size that we must deallocate before returning. struct iovec *allocatedIovec = NULL; // Attach the header and populate the iovec CCNxCodecNetworkBufferIoVec *iovec = athenaTransportLinkModule_GetMessageIoVector(ccnxMetaMessage); iovcnt = ccnxCodecNetworkBufferIoVec_GetCount((CCNxCodecNetworkBufferIoVec *) iovec); const struct iovec *networkBufferIovec = ccnxCodecNetworkBufferIoVec_GetArray((CCNxCodecNetworkBufferIoVec *) iovec); // Trivial case, single iovec element. if (iovcnt == 1) { // Header array[0].iov_len = sizeof(struct ether_header); array[0].iov_base = &header; // Message content array[1].iov_len = networkBufferIovec->iov_len; array[1].iov_base = networkBufferIovec->iov_base; messageLength = array[0].iov_len + array[1].iov_len; } else { // Allocate a new iovec if more than one vector allocatedIovec = parcMemory_Allocate(sizeof(struct iovec) * (iovcnt + 1)); array = allocatedIovec; // Header array[0].iov_len = sizeof(struct ether_header); array[0].iov_base = &header; messageLength = array[0].iov_len; // Append message content for (int i = 0; i < iovcnt; i++) { array[i + 1].iov_len = networkBufferIovec[i].iov_len; array[i + 1].iov_base = networkBufferIovec[i].iov_base; messageLength += array[i + 1].iov_len; } } iovcnt++; // increment for the header if (linkData->link.mtu) { if (messageLength > linkData->link.mtu) { if (allocatedIovec != NULL) { parcMemory_Deallocate(&allocatedIovec); } ccnxCodecNetworkBufferIoVec_Release(&iovec); errno = EMSGSIZE; return -1; } } parcLog_Debug(athenaTransportLink_GetLogger(athenaTransportLink), "sending message (size=%d)", messageLength); ssize_t writeCount = 0; writeCount = athenaEthernet_Send(linkData->athenaEthernet, array, iovcnt); ccnxCodecNetworkBufferIoVec_Release(&iovec); // Free up any storage allocated for a non-singular iovec if (allocatedIovec != NULL) { parcMemory_Deallocate(&allocatedIovec); array = NULL; } // on error close the link, else return to retry a zero write if (writeCount == -1) { if ((errno == EAGAIN) || (errno == EINTR)) { parcLog_Info(athenaTransportLink_GetLogger(athenaTransportLink), "send retry"); linkData->_stats.send_Retry++; return -1; } athenaTransportLink_SetEvent(athenaTransportLink, AthenaTransportLinkEvent_Error); parcLog_Error(athenaTransportLink_GetLogger(athenaTransportLink), "send error (%s)", strerror(errno)); linkData->_stats.send_Error++; return -1; } // Short write if (writeCount != messageLength) { linkData->_stats.send_ShortWrite++; parcLog_Debug(athenaTransportLink_GetLogger(athenaTransportLink), "short write"); return -1; } 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; }
static CCNxMetaMessage * _FIB_Command(Athena *athena, CCNxInterest *interest, PARCBitVector *ingress) { CCNxMetaMessage *responseMessage; responseMessage = athenaFIB_ProcessMessage(athena->athenaFIB, interest); if (responseMessage) { return responseMessage; } CCNxName *ccnxName = ccnxInterest_GetName(interest); if (ccnxName_GetSegmentCount(ccnxName) > AthenaCommandSegment) { CCNxNameSegment *nameSegment = ccnxName_GetSegment(ccnxName, AthenaCommandSegment); char *command = ccnxNameSegment_ToString(nameSegment); if ((strcasecmp(command, AthenaCommand_Add) == 0) || (strcasecmp(command, AthenaCommand_Remove) == 0)) { char *arguments = _get_arguments(interest); if (arguments == NULL) { responseMessage = _create_response(athena, ccnxName, "No link or prefix arguments given to %s route command", command); parcMemory_Deallocate(&command); return responseMessage; } char linkName[MAXPATHLEN]; char prefix[MAXPATHLEN]; PARCBitVector *linkVector; // {Add,Remove} Route arguments "<prefix> [<linkName>]", if linkName not specified, use the incoming link id ([de-]registration) int numberOfArguments = sscanf(arguments, "%s %s", prefix, linkName); if (numberOfArguments == 2) { int linkId = athenaTransportLinkAdapter_LinkNameToId(athena->athenaTransportLinkAdapter, linkName); if (linkId == -1) { responseMessage = _create_response(athena, ccnxName, "Unknown linkName %s", linkName); parcMemory_Deallocate(&command); parcMemory_Deallocate(&arguments); return responseMessage; } linkVector = parcBitVector_Create(); parcBitVector_Set(linkVector, linkId); } else if (numberOfArguments == 1) { // use ingress link linkVector = parcBitVector_Acquire(ingress); } else { responseMessage = _create_response(athena, ccnxName, "No prefix specified or too many arguments"); parcMemory_Deallocate(&command); parcMemory_Deallocate(&arguments); return responseMessage; } CCNxName *prefixName = ccnxName_CreateFromCString(prefix); if (prefixName == NULL) { responseMessage = _create_response(athena, ccnxName, "Unable to parse prefix %s", prefix); parcMemory_Deallocate(&command); parcMemory_Deallocate(&arguments); parcBitVector_Release(&linkVector); return responseMessage; } int result = false; if (strcasecmp(command, AthenaCommand_Add) == 0) { result = athenaFIB_AddRoute(athena->athenaFIB, prefixName, linkVector); } else if (strcasecmp(command, AthenaCommand_Remove) == 0) { result = athenaFIB_DeleteRoute(athena->athenaFIB, prefixName, linkVector); } if (result == true) { char *routePrefix = ccnxName_ToString(prefixName); const char *linkIdName = athenaTransportLinkAdapter_LinkIdToName(athena->athenaTransportLinkAdapter, parcBitVector_NextBitSet(linkVector, 0)); responseMessage = _create_response(athena, ccnxName, "%s route %s -> %s", command, routePrefix, linkIdName); athenaInterestControl_LogConfigurationChange(athena, ccnxName, "%s %s", routePrefix, linkIdName); parcMemory_Deallocate(&routePrefix); } else { responseMessage = _create_response(athena, ccnxName, "%s failed", command); } parcBitVector_Release(&linkVector); ccnxName_Release(&prefixName); parcMemory_Deallocate(&arguments); } else if (strcasecmp(command, AthenaCommand_List) == 0) { // Need to create the response here because as the FIB doesn't know the linkName parcLog_Debug(athena->log, "FIB List command invoked"); PARCList *fibEntries = athenaFIB_CreateEntryList(athena->athenaFIB); responseMessage = _create_FIBList_response(athena, ccnxName, fibEntries); parcList_Release(&fibEntries); } else { responseMessage = _create_response(athena, ccnxName, "Unknown command: %s", command); } parcMemory_Deallocate(&command); } return responseMessage; }
static CCNxMetaMessage * _create_FIBList_response(Athena *athena, CCNxName *ccnxName, PARCList *fibEntryList) { PARCJSON *jsonPayload = parcJSON_Create(); PARCJSONArray *jsonEntryList = parcJSONArray_Create(); parcJSON_AddArray(jsonPayload, JSON_KEY_RESULT, jsonEntryList); for (size_t i = 0; i < parcList_Size(fibEntryList); ++i) { AthenaFIBListEntry *entry = parcList_GetAtIndex(fibEntryList, i); if (entry != NULL) { CCNxName *prefixName = athenaFIBListEntry_GetName(entry); if (prefixName) { char *prefix = ccnxName_ToString(prefixName); int linkId = athenaFIBListEntry_GetLinkId(entry); const char *linkName = athenaTransportLinkAdapter_LinkIdToName(athena->athenaTransportLinkAdapter, linkId); parcLog_Debug(athena->log, " Route: %s->%s", prefix, linkName); PARCJSON *jsonItem = parcJSON_Create(); parcJSON_AddString(jsonItem, JSON_KEY_NAME, prefix); parcJSON_AddString(jsonItem, JSON_KEY_LINK, linkName); PARCJSONValue *jsonItemValue = parcJSONValue_CreateFromJSON(jsonItem); parcJSON_Release(&jsonItem); parcJSONArray_AddValue(jsonEntryList, jsonItemValue); parcJSONValue_Release(&jsonItemValue); parcMemory_Deallocate(&prefix); } else { int linkId = athenaFIBListEntry_GetLinkId(entry); const char *linkName = athenaTransportLinkAdapter_LinkIdToName(athena->athenaTransportLinkAdapter, linkId); parcLog_Debug(athena->log, " Route: <empty>->%s", linkName); PARCJSON *jsonItem = parcJSON_Create(); parcJSON_AddString(jsonItem, JSON_KEY_NAME, ""); parcJSON_AddString(jsonItem, JSON_KEY_LINK, linkName); PARCJSONValue *jsonItemValue = parcJSONValue_CreateFromJSON(jsonItem); parcJSON_Release(&jsonItem); parcJSONArray_AddValue(jsonEntryList, jsonItemValue); parcJSONValue_Release(&jsonItemValue); } } } char *jsonString = parcJSON_ToString(jsonPayload); parcJSONArray_Release(&jsonEntryList); parcJSON_Release(&jsonPayload); PARCBuffer *payload = parcBuffer_CreateFromArray(jsonString, strlen(jsonString)); CCNxContentObject *contentObject = ccnxContentObject_CreateWithNameAndPayload(ccnxName, parcBuffer_Flip(payload)); struct timeval tv; gettimeofday(&tv, NULL); uint64_t nowInMillis = (tv.tv_sec * 1000) + (tv.tv_usec / 1000); ccnxContentObject_SetExpiryTime(contentObject, nowInMillis + 100); // this response is good for 100 millis CCNxMetaMessage *result = ccnxMetaMessage_CreateFromContentObject(contentObject); ccnxContentObject_Release(&contentObject); parcBuffer_Release(&payload); parcMemory_Deallocate(&jsonString); athena_EncodeMessage(result); return result; }
static void _processInterest(Athena *athena, CCNxInterest *interest, PARCBitVector *ingressVector) { uint8_t hoplimit; // // * (0) Hoplimit check, exclusively on interest messages // int linkId = parcBitVector_NextBitSet(ingressVector, 0); if (athenaTransportLinkAdapter_IsNotLocal(athena->athenaTransportLinkAdapter, linkId)) { hoplimit = ccnxInterest_GetHopLimit(interest); if (hoplimit == 0) { // We should never receive a message with a hoplimit of 0 from a non-local source. parcLog_Error(athena->log, "Received a message with a hoplimit of zero from a non-local source (%s).", athenaTransportLinkAdapter_LinkIdToName(athena->athenaTransportLinkAdapter, linkId)); return; } ccnxInterest_SetHopLimit(interest, hoplimit - 1); } // // * (1) if the interest is in the ContentStore, reply and return, // assuming that other PIT entries were satisified when the content arrived. // CCNxMetaMessage *content = athenaContentStore_GetMatch(athena->athenaContentStore, interest); if (content) { const char *ingressVectorString = parcBitVector_ToString(ingressVector); parcLog_Debug(athena->log, "Forwarding content from store to %s", ingressVectorString); parcMemory_Deallocate(&ingressVectorString); PARCBitVector *result = athenaTransportLinkAdapter_Send(athena->athenaTransportLinkAdapter, content, ingressVector); if (result) { // failed channels - client will resend interest unless we wish to optimize things here parcBitVector_Release(&result); } return; } // // * (2) add it to the PIT, if it was aggregated or there was an error we're done, otherwise we // forward the interest. The expectedReturnVector is populated with information we get from // the FIB and used to verify content objects ingress ports when they arrive. // PARCBitVector *expectedReturnVector; AthenaPITResolution result; if ((result = athenaPIT_AddInterest(athena->athenaPIT, interest, ingressVector, &expectedReturnVector)) != AthenaPITResolution_Forward) { if (result == AthenaPITResolution_Error) { parcLog_Error(athena->log, "PIT resolution error"); } return; } // Divert interests destined to the forwarder, we assume these are control messages CCNxName *ccnxName = ccnxInterest_GetName(interest); if (ccnxName_StartsWith(ccnxName, athena->athenaName) == true) { _processInterestControl(athena, interest, ingressVector); return; } // // * (3) if it's in the FIB, forward, then update the PIT expectedReturnVector so we can verify // when the returned object arrives that it came from an interface it was expected from. // Interest messages with a hoplimit of 0 will never be sent out by the link adapter to a // non-local interface so we need not check that here. // ccnxName = ccnxInterest_GetName(interest); PARCBitVector *egressVector = athenaFIB_Lookup(athena->athenaFIB, ccnxName); if (egressVector != NULL) { // Remove the link the interest came from if it was included in the FIB entry parcBitVector_ClearVector(egressVector, ingressVector); // If no links remain, send a no route interest return message if (parcBitVector_NumberOfBitsSet(egressVector) == 0) { CCNxInterestReturn *interestReturn = ccnxInterestReturn_Create(interest, CCNxInterestReturn_ReturnCode_NoRoute); PARCBitVector *result = athenaTransportLinkAdapter_Send(athena->athenaTransportLinkAdapter, interestReturn, ingressVector); parcBitVector_Release(&result); ccnxInterestReturn_Release(&interestReturn); } else { parcBitVector_SetVector(expectedReturnVector, egressVector); PARCBitVector *result = athenaTransportLinkAdapter_Send(athena->athenaTransportLinkAdapter, interest, egressVector); if (result) { // remove failed channels - client will resend interest unless we wish to optimize here parcBitVector_ClearVector(expectedReturnVector, result); parcBitVector_Release(&result); } } } else { // No FIB entry found, return a NoRoute interest return and remove the entry from the PIT. CCNxInterestReturn *interestReturn = ccnxInterestReturn_Create(interest, CCNxInterestReturn_ReturnCode_NoRoute); PARCBitVector *result = athenaTransportLinkAdapter_Send(athena->athenaTransportLinkAdapter, interestReturn, ingressVector); parcBitVector_Release(&result); ccnxInterestReturn_Release(&interestReturn); const char *name = ccnxName_ToString(ccnxName); if (athenaPIT_RemoveInterest(athena->athenaPIT, interest, ingressVector) != true) { parcLog_Error(athena->log, "Unable to remove interest (%s) from the PIT.", name); } parcLog_Debug(athena->log, "Name (%s) not found in FIB and no default route. Message dropped.", name); parcMemory_Deallocate(&name); } }
static CCNxMetaMessage * _create_linkList_response(AthenaTransportLinkAdapter *athenaTransportLinkAdapter, CCNxName *ccnxName) { PARCJSONArray *jsonLinkList = parcJSONArray_Create(); for (int index = 0; index < parcArrayList_Size(athenaTransportLinkAdapter->listenerList); index++) { AthenaTransportLink *athenaTransportLink = parcArrayList_Get(athenaTransportLinkAdapter->listenerList, index); const char *linkName = athenaTransportLink_GetName(athenaTransportLink); bool notLocal = athenaTransportLink_IsNotLocal(athenaTransportLink); bool localForced = athenaTransportLink_IsForceLocal(athenaTransportLink); PARCJSON *jsonItem = parcJSON_Create(); parcJSON_AddString(jsonItem, "linkName", linkName); parcJSON_AddInteger(jsonItem, "index", -1); parcJSON_AddBoolean(jsonItem, "notLocal", notLocal); parcJSON_AddBoolean(jsonItem, "localForced", localForced); PARCJSONValue *jsonItemValue = parcJSONValue_CreateFromJSON(jsonItem); parcJSON_Release(&jsonItem); parcJSONArray_AddValue(jsonLinkList, jsonItemValue); parcJSONValue_Release(&jsonItemValue); if (notLocal) { parcLog_Debug(athenaTransportLinkAdapter->log, "\n Link listener%s: %s", localForced ? " (forced remote)" : "", linkName); } else { parcLog_Debug(athenaTransportLinkAdapter->log, "\n Link listener%s: %s", localForced ? " (forced local)" : "", linkName); } } for (int index = 0; index < parcArrayList_Size(athenaTransportLinkAdapter->instanceList); index++) { AthenaTransportLink *athenaTransportLink = parcArrayList_Get(athenaTransportLinkAdapter->instanceList, index); if (athenaTransportLink) { const char *linkName = athenaTransportLink_GetName(athenaTransportLink); bool notLocal = athenaTransportLink_IsNotLocal(athenaTransportLink); bool localForced = athenaTransportLink_IsForceLocal(athenaTransportLink); PARCJSON *jsonItem = parcJSON_Create(); parcJSON_AddString(jsonItem, "linkName", linkName); parcJSON_AddInteger(jsonItem, "index", index); parcJSON_AddBoolean(jsonItem, "notLocal", notLocal); parcJSON_AddBoolean(jsonItem, "localForced", localForced); PARCJSONValue *jsonItemValue = parcJSONValue_CreateFromJSON(jsonItem); parcJSON_Release(&jsonItem); parcJSONArray_AddValue(jsonLinkList, jsonItemValue); parcJSONValue_Release(&jsonItemValue); if (notLocal) { parcLog_Debug(athenaTransportLinkAdapter->log, "\n Link instance [%d] %s: %s", index, localForced ? "(forced remote)" : "(remote)", linkName); } else { parcLog_Debug(athenaTransportLinkAdapter->log, "\n Link instance [%d] %s: %s", index, localForced ? "(forced local)" : "(local)", linkName); } } } char *jsonString = parcJSONArray_ToString(jsonLinkList); parcJSONArray_Release(&jsonLinkList); PARCBuffer *payload = parcBuffer_CreateFromArray(jsonString, strlen(jsonString)); CCNxContentObject *contentObject = ccnxContentObject_CreateWithDataPayload(ccnxName, parcBuffer_Flip(payload)); struct timeval tv; gettimeofday(&tv, NULL); uint64_t nowInMillis = (tv.tv_sec * 1000) + (tv.tv_usec / 1000); ccnxContentObject_SetExpiryTime(contentObject, nowInMillis + 100); // this response is good for 100 millis CCNxMetaMessage *result = ccnxMetaMessage_CreateFromContentObject(contentObject); ccnxContentObject_Release(&contentObject); parcBuffer_Release(&payload); parcMemory_Deallocate(&jsonString); athena_EncodeMessage(result); 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; }
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 = ccnxWireFormatMessage_GetWireFormatBuffer(ccnxMetaMessage); if (wireFormatBuffer == NULL) { CCNxCodecNetworkBufferIoVec *iovec = ccnxWireFormatMessage_GetIoVec(ccnxMetaMessage); assertNotNull(iovec, "Null io vector"); size_t iovcnt = ccnxCodecNetworkBufferIoVec_GetCount((CCNxCodecNetworkBufferIoVec *) iovec); const struct iovec *array = ccnxCodecNetworkBufferIoVec_GetArray((CCNxCodecNetworkBufferIoVec *) iovec); // If it's a single vector wrap it in a buffer to avoid a copy if (iovcnt == 1) { wireFormatBuffer = parcBuffer_Wrap(array[0].iov_base, array[0].iov_len, 0, array[0].iov_len); } else { size_t totalbytes = 0; for (int i = 0; i < iovcnt; i++) { totalbytes += array[i].iov_len; } wireFormatBuffer = parcBuffer_Allocate(totalbytes); for (int i = 0; i < iovcnt; i++) { parcBuffer_PutArray(wireFormatBuffer, array[i].iov_len, array[i].iov_base); } parcBuffer_Flip(wireFormatBuffer); } } else { wireFormatBuffer = parcBuffer_Acquire(wireFormatBuffer); } 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 == EPIPE) { 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.receive_ShortWrite++; parcLog_Debug(athenaTransportLink_GetLogger(athenaTransportLink), "short write"); parcBuffer_Release(&wireFormatBuffer); return -1; } parcBuffer_Release(&wireFormatBuffer); return 0; }