static PARCBuffer * _encodeControlPlaneInformation(const CCNxControl *cpiControlMessage) { PARCJSON *json = ccnxControl_GetJson(cpiControlMessage); char *str = parcJSON_ToCompactString(json); // include +1 because we need the NULL byte size_t len = strlen(str) + 1; size_t packetLength = sizeof(_MetisTlvFixedHeaderV0) + sizeof(MetisTlvType) + len; PARCBuffer *packet = parcBuffer_Allocate(packetLength); _MetisTlvFixedHeaderV0 hdr; memset(&hdr, 0, sizeof(hdr)); hdr.version = 0; hdr.packetType = METIS_PACKET_TYPE_CONTROL; hdr.payloadLength = htons(len + sizeof(MetisTlvType)); parcBuffer_PutArray(packet, sizeof(hdr), (uint8_t *) &hdr); MetisTlvType tlv = { .type = htons(T_CPI), .length = htons(len) }; parcBuffer_PutArray(packet, sizeof(tlv), (uint8_t *) &tlv); parcBuffer_PutArray(packet, len, (uint8_t *) str); parcMemory_Deallocate((void **) &str); return parcBuffer_Flip(packet); }
void metisConfiguration_Receive(MetisConfiguration *config, MetisMessage *message) { assertNotNull(config, "Parameter config must be non-null"); assertNotNull(message, "Parameter message must be non-null"); assertTrue(metisMessage_GetType(message) == MetisMessagePacketType_Control, "Message must be type CPI, expected %02x got %02x", MetisMessagePacketType_Control, metisMessage_GetType(message)); CCNxControl *control = metisMessage_CreateControlMessage(message); unsigned ingressId = metisMessage_GetIngressConnectionId(message); if (metisLogger_IsLoggable(config->logger, MetisLoggerFacility_Config, PARCLogLevel_Debug)) { char *str = parcJSON_ToCompactString(ccnxControl_GetJson(control)); metisLogger_Log(config->logger, MetisLoggerFacility_Config, PARCLogLevel_Debug, __func__, "%s received %s\n", __func__, str); parcMemory_Deallocate((void **) &str); } CCNxControl *response = _processControl(config, control, ingressId); metisConfiguration_SendResponse(config, response, ingressId); ccnxControl_Release(&response); ccnxControl_Release(&control); metisMessage_Release(&message); }
CCNxControl * cpi_CreateResponse(CCNxControl *request, PARCJSON *operation) { PARCJSON *requestJson = ccnxControl_GetJson(request); // use the same key as the request uint64_t seqnum = controlPlaneInterface_GetSequenceNumber(requestJson); PARCJSONValue *value = parcJSON_GetValueByName(requestJson, cpiRequest); assertNotNull(value, "Could not get request or response"); assertTrue(parcJSONValue_IsJSON(value), "cpiRequest should be a JSON object"); PARCJSON *operationJson = parcJSONValue_GetJSON(value); PARCJSONPair *pair = parcJSON_GetPairByIndex(operationJson, 1); const PARCBuffer *opKeyBuf = parcJSONPair_GetName(pair); const char *opKey = parcBuffer_ToString(opKeyBuf); PARCJSON *response = parcJSON_Create(); parcJSON_AddInteger(response, cpiSeqnum, (int) seqnum); parcJSON_AddObject(response, opKey, operation); parcMemory_Deallocate(&opKey); PARCJSON *responseJson = parcJSON_Create(); parcJSON_AddObject(responseJson, cpiResponse, response); parcJSON_Release(&response); CCNxControl *result = ccnxControl_CreateCPIRequest(responseJson); parcJSON_Release(&responseJson); return result; }
/** * All CPI messages carry a sequence number. * * Example: * @code * <#example#> * @endcode */ uint64_t cpi_GetSequenceNumber(CCNxControl *control) { PARCJSON *json = ccnxControl_GetJson(control); return controlPlaneInterface_GetSequenceNumber(json); }
/** * You should verify that it's a CPI message with cpi_IsCpiMessage() before using this. * * Example: * @code * <#example#> * @endcode */ CpiMessageType cpi_GetMessageType(const CCNxControl *control) { PARCJSON *json = ccnxControl_GetJson(control); CpiMessageType result = controlPlaneInterface_GetCPIMessageType(json); return result; }
LONGBOW_TEST_CASE(Global, athena_ProcessControl_CPI_REGISTER_PREFIX) { PARCURI *connectionURI; Athena *athena = athena_Create(100); CCNxName *name = ccnxName_CreateFromCString("ccnx:/foo/bar"); CCNxControl *control = ccnxControl_CreateAddRouteToSelfRequest(name); // CPI_REGISTER_PREFIX CCNxMetaMessage *registerPrefixCommand = ccnxMetaMessage_CreateFromControl(control); ccnxControl_Release(&control); control = ccnxControl_CreateRemoveRouteToSelfRequest(name); // CPI_UNREGISTER_PREFIX CCNxMetaMessage *unregisterPrefixCommand = ccnxMetaMessage_CreateFromControl(control); ccnxControl_Release(&control); ccnxName_Release(&name); connectionURI = parcURI_Parse("tcp://localhost:50100/listener/name=TCPListener"); const char *result = athenaTransportLinkAdapter_Open(athena->athenaTransportLinkAdapter, connectionURI); assertTrue(result != NULL, "athenaTransportLinkAdapter_Open failed (%s)", strerror(errno)); parcURI_Release(&connectionURI); connectionURI = parcURI_Parse("tcp://localhost:50100/name=TCP_0"); result = athenaTransportLinkAdapter_Open(athena->athenaTransportLinkAdapter, connectionURI); assertTrue(result != NULL, "athenaTransportLinkAdapter_Open failed (%s)", strerror(errno)); parcURI_Release(&connectionURI); int linkId = athenaTransportLinkAdapter_LinkNameToId(athena->athenaTransportLinkAdapter, "TCP_0"); PARCBitVector *ingressVector = parcBitVector_Create(); parcBitVector_Set(ingressVector, linkId); // Call _Receive() once to prime the link. Messages are dropped until _Receive() is called once. PARCBitVector *linksRead = NULL; CCNxMetaMessage *msg = athenaTransportLinkAdapter_Receive(athena->athenaTransportLinkAdapter, &linksRead, -1); assertNull(msg, "Expected to NOT receive a message after the first call to _Receive()"); CCNxMetaMessage *cpiMessages[2]; cpiMessages[0] = registerPrefixCommand; // CPI_REGISTER_PREFIX cpiMessages[1] = unregisterPrefixCommand; // CPI_UNREGISTER_PREFIX for (int i = 0; i < 2; i++) { CCNxMetaMessage *cpiMessageToSend = cpiMessages[i]; athena_ProcessMessage(athena, cpiMessageToSend, ingressVector); ccnxMetaMessage_Release(&cpiMessageToSend); CCNxMetaMessage *ack = athenaTransportLinkAdapter_Receive(athena->athenaTransportLinkAdapter, &linksRead, -1); assertNotNull(ack, "Expected a CPI_ACK message back"); assertTrue(ccnxMetaMessage_IsControl(ack), "Expected a control message back"); parcBitVector_Release(&linksRead); PARCJSON *json = ccnxControl_GetJson(ack); const PARCJSONValue *cpiAckResult = parcJSON_GetByPath(json, "CPI_ACK/REQUEST/RESULT"); bool commandResult = parcJSONValue_GetBoolean(cpiAckResult); assertTrue(commandResult, "Expected the ACK to contain RESULT=true"); ccnxMetaMessage_Release(&ack); } parcBitVector_Release(&ingressVector); athena_Release(&athena); }
static CCNxControl * _createAck(MetisConfiguration *config, CCNxControl *control, unsigned ingressId) { PARCJSON *json = ccnxControl_GetJson(control); PARCJSON *jsonAck = cpiAcks_CreateAck(json); CCNxControl *response = ccnxControl_CreateCPIRequest(jsonAck); parcJSON_Release(&jsonAck); return response; }
/** * Return the relevant operation from a REQUEST or a REPSONSE. * Do not call on an ACK * * Example: * @code * <#example#> * @endcode */ CpiOperation cpi_GetMessageOperation(CCNxControl *control) { if (cpiConnectionEthernet_IsAddMessage(control)) { return CPI_ADD_CONNECTION_ETHERNET; } if (cpiConnectionEthernet_IsRemoveMessage(control)) { return CPI_REMOVE_CONNECTION_ETHERNET; } PARCJSON *json = ccnxControl_GetJson(control); CpiOperation result = cpi_getCPIOperation2(json); return result; }
LONGBOW_TEST_CASE(Global, cpiCancelFlow_CreateRequest) { const char truth_format[] = "{\"CPI_REQUEST\":{\"SEQUENCE\":%" PRIu64 ",\"CPI_CANCEL_FLOW\":{\"FLOW_NAME\":\"lci:/who/doesnt/like/pie\"}}}"; CCNxName *name = ccnxName_CreateFromURI("lci:/who/doesnt/like/pie"); PARCJSON *cpiRequest = cpiCancelFlow_CreateRequest(name); CCNxControl *controlRequest = ccnxControl_CreateCPIRequest(cpiRequest); PARCJSON *json = ccnxControl_GetJson(controlRequest); char buffer[1024]; sprintf(buffer, truth_format, cpi_GetSequenceNumber(controlRequest)); char *test_string = parcJSON_ToCompactString(json); assertTrue(strcmp(buffer, test_string) == 0, "Incorrect JSON, expected '%s' got '%s'", buffer, test_string); parcMemory_Deallocate((void **) &test_string); ccnxControl_Release(&controlRequest); parcJSON_Release(&cpiRequest); ccnxName_Release(&name); }
NotifyStatus * ccnxControl_GetNotifyStatus(const CCNxControl *control) { return notifyStatus_ParseJSON(ccnxControl_GetJson(control)); }
CCNxName *prefix = ccnxName_CreateFromURI("lci:/howdie/stranger"); unsigned ifidx = 55; CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 }); struct timeval lifetime = { 3600, 0 }; unsigned cost = 200; CPIRouteEntry *route = cpiRouteEntry_Create(prefix, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, &lifetime, cost); CCNxControl *control = ccnxControl_CreateAddRouteRequest(route); // get its sequence number uint64_t seqnum = cpi_GetSequenceNumber(control); sprintf(truth, truth_format, seqnum); PARCJSON *test_json = ccnxControl_GetJson(control); char *test = parcJSON_ToCompactString(test_json); assertTrue(strcasecmp(truth, test) == 0, "Expected '%s', actual '%s'", truth, test); parcMemory_Deallocate((void **) &test); ccnxControl_Release(&control); cpiRouteEntry_Destroy(&route); cpiAddress_Destroy(&nexthop); } /** * Add route without lifeitme */ LONGBOW_TEST_CASE(Global, cpiForwarding_AddRoute_2) { // The JSON representation depends on the system sockaddr_in format, which