aboutsummaryrefslogtreecommitdiffstats
path: root/libccnx-transport-rta/ccnx/api/control/cpi_Listener.c
diff options
context:
space:
mode:
Diffstat (limited to 'libccnx-transport-rta/ccnx/api/control/cpi_Listener.c')
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_Listener.c432
1 files changed, 432 insertions, 0 deletions
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_Listener.c b/libccnx-transport-rta/ccnx/api/control/cpi_Listener.c
new file mode 100644
index 00000000..d8b75f9d
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_Listener.c
@@ -0,0 +1,432 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include <config.h>
+#include <stdio.h>
+
+#include <LongBow/runtime.h>
+
+#include <ccnx/api/control/cpi_Listener.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_JSON.h>
+
+#include <ccnx/api/control/controlPlaneInterface.h>
+extern uint64_t cpi_GetNextSequenceNumber(void);
+
+// JSON keys
+static const char *KEY_IFNAME = "IFNAME";
+static const char *KEY_SYMBOLIC = "SYMBOLIC";
+static const char *KEY_ETHERTYPE = "ETHERTYPE";
+
+static const char *KEY_IP_PROTOCOL = "IPROTO";
+static const char *KEY_ADDR = "ADDR";
+
+static const char *KEY_ADDLISTENER = "AddListener";
+static const char *KEY_REMOVELISTENER = "RemoveListener";
+
+typedef enum {
+ CPIListenerMode_ETHER,
+ CPIListenerMode_IP
+} _CPIListenerMode;
+
+struct cpi_listener {
+ _CPIListenerMode mode;
+ char *symbolic;
+
+ char *interfaceName;
+ uint16_t ethertype;
+
+ CPIAddress *address;
+ CPIInterfaceIPTunnelType type;
+};
+
+CPIListener *
+cpiListener_CreateEther(const char *interfaceName, uint16_t ethertype, const char *symbolic)
+{
+ assertNotNull(interfaceName, "Parameter interfaceName must be non-null");
+ assertNotNull(symbolic, "Parameter symbolic must be non-null");
+
+ CPIListener *listener = parcMemory_AllocateAndClear(sizeof(CPIListener));
+ if (listener) {
+ listener->mode = CPIListenerMode_ETHER;
+ listener->interfaceName = parcMemory_StringDuplicate(interfaceName, strlen(interfaceName));
+ listener->symbolic = parcMemory_StringDuplicate(symbolic, strlen(symbolic));
+ listener->ethertype = ethertype;
+ }
+
+ return listener;
+}
+
+CPIListener *
+cpiListener_CreateIP(CPIInterfaceIPTunnelType type, CPIAddress *localAddress, const char *symbolic)
+{
+ assertNotNull(localAddress, "Parameter peerLinkAddress must be non-null");
+ assertNotNull(symbolic, "Parameter symbolic must be non-null");
+
+ CPIListener *listener = parcMemory_AllocateAndClear(sizeof(CPIListener));
+ if (listener) {
+ listener->mode = CPIListenerMode_IP;
+ listener->type = type;
+ listener->symbolic = parcMemory_StringDuplicate(symbolic, strlen(symbolic));
+ listener->address = cpiAddress_Copy(localAddress);
+ }
+
+ return listener;
+}
+
+void
+cpiListener_Release(CPIListener **listenerPtr)
+{
+ assertNotNull(listenerPtr, "Parameter listenerPtr must be non-null double pointer");
+ assertNotNull(*listenerPtr, "Parameter listenerPtr dereference to non-null pointer");
+
+ CPIListener *listener = *listenerPtr;
+
+ if (listener->symbolic) {
+ parcMemory_Deallocate((void **) &listener->symbolic);
+ }
+
+ if (listener->interfaceName) {
+ parcMemory_Deallocate((void **) &listener->interfaceName);
+ }
+
+ if (listener->address) {
+ cpiAddress_Destroy(&listener->address);
+ }
+
+ parcMemory_Deallocate((void **) &listener);
+ *listenerPtr = NULL;
+}
+
+bool
+cpiListener_Equals(const CPIListener *a, const CPIListener *b)
+{
+ if ((a == NULL && b == NULL) || a == b) {
+ // both null or identically equal
+ return true;
+ }
+
+ if (a == NULL || b == NULL) {
+ // only one is null
+ return false;
+ }
+
+ bool equals = false;
+ if (a->mode == b->mode) {
+ if (strcmp(a->symbolic, b->symbolic) == 0) {
+ if (a->mode == CPIListenerMode_ETHER) {
+ if (a->ethertype == b->ethertype) {
+ if (strcmp(a->interfaceName, b->interfaceName) == 0) {
+ equals = true;
+ }
+ }
+ } else {
+ if (a->type == b->type) {
+ if (cpiAddress_Equals(a->address, b->address)) {
+ equals = true;
+ }
+ }
+ }
+ }
+ }
+
+ return equals;
+}
+
+static void
+_encodeEther(const CPIListener *listener, PARCJSON *json)
+{
+ // ------ Interface Name
+ parcJSON_AddString(json, KEY_IFNAME, listener->interfaceName);
+
+ // ------ EtherType
+ parcJSON_AddInteger(json, KEY_ETHERTYPE, listener->ethertype);
+
+ // ------ Symbolic Name
+ parcJSON_AddString(json, KEY_SYMBOLIC, listener->symbolic);
+}
+
+static void
+_encodeIP(const CPIListener *listener, PARCJSON *json)
+{
+ // ------ Tunnel Type
+ const char *str = cpiInterfaceIPTunnel_TypeToString(listener->type);
+ parcJSON_AddString(json, KEY_IP_PROTOCOL, str);
+
+ // ------ Address
+ PARCJSON *addressJson = cpiAddress_ToJson(listener->address);
+ parcJSON_AddObject(json, KEY_ADDR, addressJson);
+ parcJSON_Release(&addressJson);
+
+ // ------ Symbolic Name
+ parcJSON_AddString(json, KEY_SYMBOLIC, listener->symbolic);
+}
+
+
+
+static PARCJSON *
+_cpiListener_ToJson(const CPIListener *listener)
+{
+ PARCJSON *json = parcJSON_Create();
+
+ if (listener->mode == CPIListenerMode_ETHER) {
+ _encodeEther(listener, json);
+ } else {
+ _encodeIP(listener, json);
+ }
+
+ return json;
+}
+
+/*
+ * We want to create a JSON object that looks like this, where the operationName is either
+ * AddListener or RemoveListener.
+ *
+ * {
+ * "CPI_REQUEST" :
+ * { "SEQUENCE" : <sequence number>,
+ * <operationName> : { "IFNAME" : "em1", "SYMBOLIC" : "conn0", "PEER_ADDR" : { "ADDRESSTYPE" : "LINK", "DATA" : "AQIDBAUG" }, "ETHERTYPE" : 2049 },
+ * }
+ * }
+ */
+static CCNxControl *
+_cpiListener_CreateControlMessage(const CPIListener *listener, const char *operationName)
+{
+ PARCJSON *cpiRequest = parcJSON_Create();
+
+ // --- add the seqnum
+
+ uint64_t seqnum = cpi_GetNextSequenceNumber();
+ parcJSON_AddInteger(cpiRequest, "SEQUENCE", (int) seqnum);
+
+ // -- Add the operation
+
+ PARCJSON *operation = _cpiListener_ToJson(listener);
+ parcJSON_AddObject(cpiRequest, operationName, operation);
+ parcJSON_Release(&operation);
+
+ // -- Do the final encapusulation
+
+ PARCJSON *final = parcJSON_Create();
+ parcJSON_AddObject(final, cpiRequest_GetJsonTag(), cpiRequest);
+
+ // -- Create the CPIControlMessage
+ char *finalString = parcJSON_ToString(final);
+
+ parcJSON_Release(&cpiRequest);
+ parcJSON_Release(&final);
+
+ PARCJSON *oldJson = parcJSON_ParseString(finalString);
+ CCNxControl *result = ccnxControl_CreateCPIRequest(oldJson);
+ parcJSON_Release(&oldJson);
+
+ parcMemory_Deallocate((void **) &finalString);
+
+ return result;
+}
+
+CCNxControl *
+cpiListener_CreateAddMessage(const CPIListener *etherConn)
+{
+ assertNotNull(etherConn, "Parameter etherConn must be non-null");
+ CCNxControl *control = _cpiListener_CreateControlMessage(etherConn, KEY_ADDLISTENER);
+ return control;
+}
+
+CCNxControl *
+cpiListener_CreateRemoveMessage(const CPIListener *etherConn)
+{
+ assertNotNull(etherConn, "Parameter etherConn must be non-null");
+ CCNxControl *control = _cpiListener_CreateControlMessage(etherConn, KEY_REMOVELISTENER);
+ return control;
+}
+
+static bool
+_cpiListener_IsMessageType(const CCNxControl *control, const char *operationName)
+{
+ bool isOperation = false;
+ if (ccnxControl_IsCPI(control)) {
+ PARCJSON *oldJson = ccnxControl_GetJson(control);
+ PARCJSONValue *value = parcJSON_GetValueByName(oldJson, cpiRequest_GetJsonTag());
+ if (value != NULL) {
+ // the second array element is the key we're looking for
+ PARCJSON *innerJson = parcJSONValue_GetJSON(value);
+ PARCJSONPair *opPair = parcJSON_GetPairByIndex(innerJson, 1);
+ PARCBuffer *sBuf = parcJSONPair_GetName(opPair);
+ const char *operation = parcBuffer_Overlay(sBuf, 0);
+ if (operation && strcasecmp(operation, operationName) == 0) {
+ isOperation = true;
+ }
+ }
+ }
+
+ return isOperation;
+}
+
+bool
+cpiListener_IsAddMessage(const CCNxControl *control)
+{
+ assertNotNull(control, "Parameter control must be non-null");
+ return _cpiListener_IsMessageType(control, KEY_ADDLISTENER);
+}
+
+bool
+cpiListener_IsRemoveMessage(const CCNxControl *control)
+{
+ assertNotNull(control, "Parameter control must be non-null");
+ return _cpiListener_IsMessageType(control, KEY_REMOVELISTENER);
+}
+
+static CPIListener *
+_parseEther(PARCJSON *json)
+{
+ PARCJSONValue *value = parcJSON_GetValueByName(json, KEY_IFNAME);
+ PARCBuffer *sBuf = parcJSONValue_GetString(value);
+ const char *ifname = parcBuffer_Overlay(sBuf, 0);
+
+ value = parcJSON_GetValueByName(json, KEY_SYMBOLIC);
+ sBuf = parcJSONValue_GetString(value);
+ const char *symbolic = parcBuffer_Overlay(sBuf, 0);
+
+ value = parcJSON_GetValueByName(json, KEY_ETHERTYPE);
+ int ethertype = (int) parcJSONValue_GetInteger(value);
+
+ CPIListener *listener = cpiListener_CreateEther(ifname, (uint16_t) ethertype, symbolic);
+ return listener;
+}
+
+static CPIListener *
+_parseIP(PARCJSON *json)
+{
+ PARCJSONValue *value = parcJSON_GetValueByName(json, KEY_ADDR);
+ assertNotNull(value,
+ "JSON key not found %s: %s",
+ KEY_ADDR,
+ parcJSON_ToString(json));
+ PARCJSON *addrJson = parcJSONValue_GetJSON(value);
+
+ CPIAddress *address = cpiAddress_CreateFromJson(addrJson);
+ assertNotNull(address, "Failed to decode the address from %s", parcJSON_ToString(addrJson));
+
+ value = parcJSON_GetValueByName(json, KEY_SYMBOLIC);
+ PARCBuffer *sBuf = parcJSONValue_GetString(value);
+ const char *symbolic = parcBuffer_Overlay(sBuf, 0);
+
+ value = parcJSON_GetValueByName(json, KEY_IP_PROTOCOL);
+ sBuf = parcJSONValue_GetString(value);
+ const char *typeString = parcBuffer_Overlay(sBuf, 0);
+
+ CPIInterfaceIPTunnelType type = cpiInterfaceIPTunnel_TypeFromString(typeString);
+
+ CPIListener *listener = cpiListener_CreateIP(type, address, symbolic);
+ cpiAddress_Destroy(&address);
+
+ return listener;
+}
+
+
+CPIListener *
+cpiListener_FromControl(const CCNxControl *control)
+{
+ assertNotNull(control, "Parameter control must be non-null");
+
+ CPIListener *listener = NULL;
+
+ if (ccnxControl_IsCPI(control)) {
+ PARCJSON *oldJson = ccnxControl_GetJson(control);
+ PARCJSONValue *value = parcJSON_GetValueByName(oldJson, cpiRequest_GetJsonTag());
+
+ if (value != NULL) {
+ PARCJSON *innerJson = parcJSONValue_GetJSON(value);
+ // the second array element is the key we're looking for
+ value = parcJSON_GetValueByName(innerJson, KEY_ADDLISTENER);
+ if (value == NULL) {
+ value = parcJSON_GetValueByName(innerJson, KEY_REMOVELISTENER);
+ }
+ if (value != NULL) {
+ PARCJSON *operationJson = parcJSONValue_GetJSON(value);
+
+ // if it has an interface name it's an ether
+ value = parcJSON_GetValueByName(operationJson, KEY_IFNAME);
+ if (value != NULL) {
+ listener = _parseEther(operationJson);
+ } else {
+ listener = _parseIP(operationJson);
+ }
+ }
+ }
+ }
+
+ return listener;
+}
+
+const char *
+cpiListener_GetInterfaceName(const CPIListener *listener)
+{
+ assertNotNull(listener, "Parameter listener must be non-null");
+ return listener->interfaceName;
+}
+
+const char *
+cpiListener_GetSymbolicName(const CPIListener *listener)
+{
+ assertNotNull(listener, "Parameter listener must be non-null");
+ return listener->symbolic;
+}
+
+CPIAddress *
+cpiListener_GetAddress(const CPIListener *listener)
+{
+ assertNotNull(listener, "Parameter listener must be non-null");
+ return listener->address;
+}
+
+uint16_t
+cpiListener_GetEtherType(const CPIListener *listener)
+{
+ assertNotNull(listener, "Parameter listener must be non-null");
+ return listener->ethertype;
+}
+
+bool
+cpiListener_IsEtherEncap(const CPIListener *listener)
+{
+ assertNotNull(listener, "Parameter listener must be non-null");
+ return listener->mode == CPIListenerMode_ETHER;
+}
+
+
+bool
+cpiListener_IsIPEncap(const CPIListener *listener)
+{
+ assertNotNull(listener, "Parameter listener must be non-null");
+ return listener->mode == CPIListenerMode_IP;
+}
+
+bool
+cpiListener_IsProtocolUdp(const CPIListener *listener)
+{
+ assertNotNull(listener, "Parameter listener must be non-null");
+ return (listener->mode == CPIListenerMode_IP && listener->type == IPTUN_UDP);
+}
+
+bool
+cpiListener_IsProtocolTcp(const CPIListener *listener)
+{
+ assertNotNull(listener, "Parameter listener must be non-null");
+ return (listener->mode == CPIListenerMode_IP && listener->type == IPTUN_TCP);
+}
+