LONGBOW_TEST_CASE(Dictionary, component_Codec_Tlv_Upcall_Read_Control) { TestData *data = longBowTestCase_GetClipBoardData(testCase); PARCBuffer *wireFormat = parcBuffer_Wrap(v1_cpi_add_route_crc32c, sizeof(v1_cpi_add_route_crc32c), 0, sizeof(v1_cpi_add_route_crc32c)); CCNxTlvDictionary *dictionary = ccnxWireFormatMessage_FromControlPacketType(CCNxTlvDictionary_SchemaVersion_V1, wireFormat); parcBuffer_Release(&wireFormat); // We have not set the message type or schema TransportMessage *tm = transportMessage_CreateFromDictionary(dictionary); transportMessage_SetInfo(tm, data->mock->connection, NULL); ccnxTlvDictionary_Release(&dictionary); // ------ // Now do the actual test of sending the transport message up the stack TransportMessage *test_tm = sendUp(data, tm); // It should now be parsed into an control message CCNxTlvDictionary *testdict = transportMessage_GetDictionary(test_tm); assertNotNull(testdict, "Failed to get dictionary from the transport message"); assertTrue(ccnxTlvDictionary_IsControl(testdict), "Dictionary says it is not a Control"); assertTrue(ccnxTlvDictionary_GetSchemaVersion(testdict) == CCNxTlvDictionary_SchemaVersion_V1, "Wrong schema, got %d expected %d", ccnxTlvDictionary_GetSchemaVersion(testdict), CCNxTlvDictionary_SchemaVersion_V1); transportMessage_Destroy(&tm); }
static void _assertInvariants(const CCNxTlvDictionary *interestDictionary) { assertNotNull(interestDictionary, "Dictionary is null"); assertTrue((ccnxTlvDictionary_IsInterest(interestDictionary) || ccnxTlvDictionary_IsInterestReturn(interestDictionary)), "Dictionary is not an interest"); assertTrue(ccnxTlvDictionary_GetSchemaVersion(interestDictionary) == CCNxTlvDictionary_SchemaVersion_V1, "Dictionary is wrong schema Interest, got %d expected %d", ccnxTlvDictionary_GetSchemaVersion(interestDictionary), CCNxTlvDictionary_SchemaVersion_V1); }
// // 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; }
CCNxInterestReturnInterface * ccnxInterestReturnInterface_GetInterface(const CCNxTlvDictionary *dictionary) { assertTrue(ccnxTlvDictionary_IsInterestReturn(dictionary), "Expected an InterestReturn"); CCNxInterestReturnInterface *impl = ccnxTlvDictionary_GetMessageInterface(dictionary); if (!impl) { // If we're here, we need to update the interface pointer. Break the const. // We're not changing data values, just initializing the Interface pointer. // Figure out what the typeInterface should be, based on the attributes we know. int schemaVersion = ccnxTlvDictionary_GetSchemaVersion(dictionary); switch (schemaVersion) { case CCNxTlvDictionary_SchemaVersion_V0: trapUnexpectedState("ccnxInterestReturnInterface_GetInterface() not implemented for V0"); case CCNxTlvDictionary_SchemaVersion_V1: impl = &CCNxInterestReturnFacadeV1_Implementation; break; default: trapUnexpectedState("Unknown SchemaVersion encountered in ccnxInterestReturnInterface_GetInterface()"); break; } if (impl) { ccnxTlvDictionary_SetMessageInterface((CCNxTlvDictionary *) dictionary, impl); // break the const. } } return impl; }
bool ccnxValidationHmacSha256_Test(const CCNxTlvDictionary *message) { switch (ccnxTlvDictionary_GetSchemaVersion(message)) { case CCNxTlvDictionary_SchemaVersion_V1: { if (ccnxTlvDictionary_IsValueInteger(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE)) { uint64_t cryptosuite = ccnxTlvDictionary_GetInteger(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE); return (cryptosuite == PARCCryptoSuite_HMAC_SHA256); } return false; } default: trapIllegalValue(message, "Unknown schema version: %d", ccnxTlvDictionary_GetSchemaVersion(message)); } return false; }
LONGBOW_TEST_CASE(Global, ccnxWireFormatMessage_FromInterestPacketTypeIoVec) { uint8_t data[64]; uint8_t pad[32]; CCNxCodecNetworkBufferIoVec *vec = _createNetworkBufferIoVec(512, 32, pad, 64, data); CCNxWireFormatMessage *message = ccnxWireFormatMessage_FromInterestPacketTypeIoVec(CCNxTlvDictionary_SchemaVersion_V1, vec); assertNotNull(message, "Got null CCNxWireFormatMessage"); assertTrue(ccnxTlvDictionary_IsInterest(message), "Wrong message type"); assertTrue(ccnxTlvDictionary_GetSchemaVersion(message) == CCNxTlvDictionary_SchemaVersion_V1, "Wrong schema, got %d expected %d", ccnxTlvDictionary_GetSchemaVersion(message), CCNxTlvDictionary_SchemaVersion_V1); ccnxWireFormatMessage_Release(&message); ccnxCodecNetworkBufferIoVec_Release(&vec); }
/** * Sets the Validation algorithm to HMAC with SHA-256 hash * * Sets the validation algorithm to be HMAC with a SHA-256 digest. Optionally includes * a KeyId with the message. * * @param [in] message The message dictionary * @param [in] keyid (Optional) The KEYID to include the the message * * @return <#value#> <#explanation#> * * Example: * @code * <#example#> * @endcode */ bool ccnxValidationHmacSha256_Set(CCNxTlvDictionary *message, const PARCBuffer *keyid) { bool success = true; switch (ccnxTlvDictionary_GetSchemaVersion(message)) { case CCNxTlvDictionary_SchemaVersion_V1: { success &= ccnxTlvDictionary_PutInteger(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE, PARCCryptoSuite_HMAC_SHA256); if (keyid) { success &= ccnxTlvDictionary_PutBuffer(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYID, keyid); } break; } default: trapIllegalValue(message, "Unknown schema version: %d", ccnxTlvDictionary_GetSchemaVersion(message)); } return success; }
// // 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; }
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 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; }