Scheduled maintenance on Saturday, 27 September 2025, from 07:00 AM to 4:00 PM GMT (09:00 AM to 6:00 PM CEST) - some services may be unavailable -

Skip to content
Snippets Groups Projects
pathComp_RESTapi.c 74.9 KiB
Newer Older
  • Learn to ignore specific revisions
  • Ricardo Martínez's avatar
    Ricardo Martínez committed
    			DEBUG_PC("Operational Status: %d (0 Undefined, 1 Disabled, 2 Enabled", d->operational_status);
    		}
    
    
    		// Get the device UUID
    		cJSON* deviceUuidObj = cJSON_GetObjectItem(item, "device_Id");
    		if (cJSON_IsString(deviceUuidObj)) {
    			duplicate_string(d->deviceId, deviceUuidObj->valuestring);
    
    			DEBUG_PC("Device (%d) -- Id: %s (uuid string format)", i + 1, d->deviceId);
    
    		}
    
    		// Get the device Type
    		cJSON* deviceTypeObj = cJSON_GetObjectItem(item, "device_type");
    		if (cJSON_IsString(deviceTypeObj)) {
    			duplicate_string(d->deviceType, deviceTypeObj->valuestring);
    			//DEBUG_PC("  Device Type: %s ---", d->deviceType);
    		}
    
    		DEBUG_PC("DeviceId: %s, Device Type: %s", d->deviceId, d->deviceType);
    
    
    		// get the device endPoints
    		cJSON* deviceEndpointsArray = cJSON_GetObjectItem(item, "device_endpoints");
    
    		if (cJSON_IsArray(deviceEndpointsArray)) {
    
    			parse_json_device_endpoints_array(deviceEndpointsArray, d);
    		}
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    		// append the device into the deviceList
    		deviceList = g_list_append(deviceList, d);
    
    	}
    	return;
    }
    
    ///////////////////////////////////////////////////////////////////////////////////////
    /**
     * 	@file pathComp_RESTapi.c
     * 	@brief Function used to parse the JSON objects the endPoint of a link
     *
     * 	@param endPointsLinkObj
     *  @param l
     *
     *	@author Ricardo Martínez <ricardo.martinez@cttc.es>
     *	@date 2022
     */
     /////////////////////////////////////////////////////////////////////////////////////////
    void parse_json_link_endpoints_array(cJSON *endPointsLinkObj, struct link_t* l) {
    	for (gint i = 0; i < cJSON_GetArraySize(endPointsLinkObj); i++) {
    
    		//DEBUG_PC("link: %s has %d endPointIds", l->linkId, l->numLinkEndPointIds);
    
    		l->numLinkEndPointIds++;
    
    		struct link_endpointId_t* endPointLink = &(l->linkEndPointId[i]);
    
    		cJSON* item = cJSON_GetArrayItem(endPointsLinkObj, i);
    
    		// Get endPoint attributes (topologyId, deviceId, endpoint_uuid)
    		cJSON* endPointIdObj = cJSON_GetObjectItem(item, "endpoint_id");
    		if (cJSON_IsObject(endPointIdObj)) {
    			// Get the topology Id Object
    			cJSON* topologyIdObj = cJSON_GetObjectItem(endPointIdObj, "topology_id");
    			if (cJSON_IsObject(topologyIdObj)) {
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    				parse_topology_Id(topologyIdObj, &endPointLink->topology_id);				
    
    			}
    			// Get the deviceId
    			cJSON* deviceIdObj = cJSON_GetObjectItem(endPointIdObj, "device_id");
    			if (cJSON_IsString(deviceIdObj)) {
    				duplicate_string(endPointLink->deviceId, deviceIdObj->valuestring);
    
    				DEBUG_PC("   Link Endpoint[%d] -- DeviceId: %s", i + 1, endPointLink->deviceId);
    
    			}
    			// Get the endpoint_uuid
    			cJSON* endPointUuidObj = cJSON_GetObjectItem(endPointIdObj, "endpoint_uuid");
    			if (cJSON_IsString(endPointUuidObj)) {
    				duplicate_string(endPointLink->endPointId, endPointUuidObj->valuestring);
    				//DEBUG_PC("Link Endpoint (%d) -- EndPoint Uuid: %s (uuid)", i + 1, endPointLink->endPointId);
    			}
    		}
    	}
    
    	//DEBUG_PC("link id: %s has %d endpoints", l->linkId, l->numLinkEndPointIds);
    
    	return;
    }
    
    ///////////////////////////////////////////////////////////////////////////////////////
    /**
     * 	@file pathComp_RESTapi.c
     * 	@brief Function used to parse the JSON objects describing the set of links
     *
     * 	@param linkListArray
     *
     *	@author Ricardo Martínez <ricardo.martinez@cttc.es>
     *	@date 2022
     */
     /////////////////////////////////////////////////////////////////////////////////////////
    void parsing_json_linkList_array(cJSON* linkListArray) {
    
    	DEBUG_PC("");
    	DEBUG_PC("======= PARSING OF THE LINK LIST ARRAY ==========");
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	for (gint i = 0; i < cJSON_GetArraySize(linkListArray); i++) {		
    		struct link_t* l = g_malloc0(sizeof(struct link_t));
    		if (l == NULL) {
    			DEBUG_PC("Memory Allocation Failure");
    			exit(-1);
    		}
    
    		cJSON* item = cJSON_GetArrayItem(linkListArray, i);
    
    		// Get the link Id (uuid)
    		cJSON* linkIdObj = cJSON_GetObjectItem(item, "link_Id");
    
    			duplicate_string(l->linkId, linkIdObj->valuestring);
    
    			DEBUG_PC(" * Link (%d) -- Id: %s (uuid)", i + 1, l->linkId);
    
    		// Get the link endpoints (assumed to be p2p)
    		cJSON* endPointsLinkObj = cJSON_GetObjectItem(item, "link_endpoint_ids");
    		if (cJSON_IsArray(endPointsLinkObj)) {
    
    			//DEBUG_PC("number linkEndPointIds: %d", l->numLinkEndPointIds);
    
    			parse_json_link_endpoints_array(endPointsLinkObj, l);
    		}
    		// get the fowarding direction
    		cJSON* fwdDirObj = cJSON_GetObjectItem(item, "forwarding_direction");
    		if (cJSON_IsNumber(fwdDirObj)) {
    			l->forwarding_direction = (guint)(fwdDirObj->valuedouble);
    			print_link_forwarding_direction(l->forwarding_direction);
    		}
    		// total potential capacity
    		cJSON* totalPotentialCapacityObj = cJSON_GetObjectItem(item, "total-potential-capacity");
    		if (cJSON_IsObject(totalPotentialCapacityObj))
    		{
    			parse_capacity_object(totalPotentialCapacityObj, &l->potential_capacity);
    			//DEBUG_PC("Link (%d) -- Potential Capacity: %f", i + 1, l->potential_capacity.value);
    			print_capacity_unit(l->potential_capacity.unit);
    		}
    		// total available capacity
    		cJSON* availableCapacityObj = cJSON_GetObjectItem(item, "available-capacity");
    		if (cJSON_IsObject(availableCapacityObj))
    		{
    			parse_capacity_object(availableCapacityObj, &l->available_capacity);
    			//DEBUG_PC("Link (%d) -- Available Capacity: %f", i + 1, l->available_capacity.value);
    			print_capacity_unit(l->available_capacity.unit);
    		}
    		// Cost Characteristics
    		cJSON* costCharacObj = cJSON_GetObjectItem(item, "cost-characteristics");
    		if (cJSON_IsObject(costCharacObj)) {
    			// Cost Name
    			cJSON* costNameObj = cJSON_GetObjectItem(costCharacObj, "cost-name");
    			if (cJSON_IsString(costNameObj)) {
    				duplicate_string(l->cost_characteristics.cost_name, costNameObj->valuestring);
    				//DEBUG_PC("Link (%d) -- Cost Name: %s", i + 1, l->cost_characteristics.cost_name);
    			}
    			// Cost value
    			cJSON* costValueObj = cJSON_GetObjectItem(costCharacObj, "cost-value");
    			if (cJSON_IsString(costValueObj)) {
    				char* endpr;
    				l->cost_characteristics.cost_value = (gdouble)(strtod(costValueObj->valuestring, &endpr));
    				//DEBUG_PC("Link (%d) -- Cost Value: %f", i + 1, l->cost_characteristics.cost_value);
    			}
    			// Cost Algorithm
    			cJSON* costAlgObj = cJSON_GetObjectItem(costCharacObj, "cost-algorithm");
    			if (cJSON_IsString(costAlgObj)) {
    				char* endpr;
    				l->cost_characteristics.cost_algorithm = (gdouble)(strtod(costAlgObj->valuestring, &endpr));
    				//DEBUG_PC("Link (%d) -- Cost Algorithm: %f", i + 1, l->cost_characteristics.cost_algorithm);
    			}
    		}
    		// Latency Characteristics
    		cJSON* latencyCharacObj = cJSON_GetObjectItem(item, "latency-characteristics");
    		if (cJSON_IsObject(latencyCharacObj)) {
    			cJSON* fixedLatencyCharacObj = cJSON_GetObjectItem(latencyCharacObj, "fixed-latency-characteristic");
    			if (cJSON_IsString(fixedLatencyCharacObj)) {
    				char* endpr;
    				l->latency_characteristics.fixed_latency = (gdouble)(strtod(fixedLatencyCharacObj->valuestring, &endpr));
    				//DEBUG_PC("Link (%d) -- Latency: %f", i + 1, l->latency_characteristics.fixed_latency);
    			}	
    		}
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    		linkList = g_list_append(linkList, l);
    
    ///////////////////////////////////////////////////////////////////////////////////////
    /**
     * 	@file pathComp_RESTapi.c
     * 	@brief Function used to generate the reverse (unidirecitonal) link from those being learnt
     *  from the received context
     *
     *	@author Ricardo Martínez <ricardo.martinez@cttc.es>
     *	@date 2022
     */
     ////////////////////////////////////////////////////////////////////////////////////////
    void generate_reverse_linkList() {
    
    	DEBUG_PC("");
    	DEBUG_PC("CREATION OF REVERSE LINKS");
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	gint numLinks = g_list_length (linkList);
    	DEBUG_PC("Initial Number of links in the main List: %d", numLinks);
    	gint i = 0;
    	for (GList* ln = g_list_first(linkList);
    		(ln) && (i < numLinks);
    		ln = g_list_next(ln), i++)
    	{
    		struct link_t* refLink = (struct link_t*)(ln->data);
    		struct link_t* newLink = g_malloc0(sizeof(struct link_t));
    		if (newLink == NULL) {
    			DEBUG_PC("Memory Allocation Failure");
    			exit(-1);
    		}
    
    		// Copy the linkId + appending "_rev"
    		duplicate_string(newLink->linkId, refLink->linkId);
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    		strcat(newLink->linkId, "_rev"); 		
    
    
    		//DEBUG_PC("refLink: %s // newLink: %s", refLink->linkId, newLink->linkId);
    
    		// Assumption: p2p links. The newLink endpoints are the reversed ones form the reference Link (refLink)
    		// i.e., refLink A->B, then newLink B->A
    
    		//DEBUG_PC("ref: %s has %d endpoints", refLink->linkId, refLink->numLinkEndPointIds);
    #if 1
    
    		if (refLink->numLinkEndPointIds != 2) {
    
    			DEBUG_PC("To construct the new Link from ref: %s, 2 EndPoints are a MUST", refLink->linkId);
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    		//DEBUG_PC(" * Link[%d] -- Id: %s", numLinks + i, newLink->linkId);
    
    		//DEBUG_PC("Number of Endpoints in Link: %d", refLink->numLinkEndPointIds);
    
    		for (gint j = refLink->numLinkEndPointIds - 1, m = 0; j >= 0; j--, m++) {			
    
    			struct link_endpointId_t* refEndPId = &(refLink->linkEndPointId[j]);
    			struct link_endpointId_t* newEndPId = &(newLink->linkEndPointId[m]);
    			// Duplicate the topologyId information, i.e., contextId and topology_uuid
    			duplicate_string(newEndPId->topology_id.contextId, refEndPId->topology_id.contextId);
    			duplicate_string(newEndPId->topology_id.topology_uuid, refEndPId->topology_id.topology_uuid);
    			//duplicate the deviceId and endPoint_uuid
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    			duplicate_string(newEndPId->deviceId, refEndPId->endPointId);
    			duplicate_string(newEndPId->endPointId, refEndPId->deviceId);
    			//DEBUG_PC("refLink Endpoint[%d]: %s(%s)", j, refEndPId->deviceId, refEndPId->endPointId);
    
    			//DEBUG_PC("newLink Endpoint[%d]: %s(%s)", m, newEndPId->deviceId, newEndPId->endPointId);
    			newLink->numLinkEndPointIds++;
    		}
    
    		// duplicate forwarding direction
    		newLink->forwarding_direction = refLink->forwarding_direction;
    
    		// duplicate capacity attributes
    		memcpy(&newLink->potential_capacity.value, &refLink->potential_capacity.value, sizeof(gdouble));
    		newLink->potential_capacity.unit = refLink->potential_capacity.unit;
    
    		memcpy(&newLink->available_capacity.value, &refLink->available_capacity.value, sizeof(gdouble));
    		newLink->available_capacity.unit = refLink->available_capacity.unit;
    
    		// duplicate cost characteristics
    		memcpy(&newLink->cost_characteristics.cost_value, &refLink->cost_characteristics.cost_value, sizeof(gdouble));
    		memcpy(&newLink->cost_characteristics.cost_algorithm, &refLink->cost_characteristics.cost_algorithm, sizeof(gdouble));
    		duplicate_string(newLink->cost_characteristics.cost_name, refLink->cost_characteristics.cost_name);
    
    		// duplicate latency characteristics
    		memcpy(&newLink->latency_characteristics.fixed_latency, &refLink->latency_characteristics.fixed_latency, sizeof(gdouble));
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    		// Append in the linkList the new creted Link
    		linkList = g_list_append(linkList, newLink);
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	DEBUG_PC("Terminating Reverse Links [total links: %d]", g_list_length(linkList));
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    ///////////////////////////////////////////////////////////////////////////////////////
    /**
     * 	@file pathComp_RESTapi.c
     * 	@brief Function used to parse the JSON object/s for active services
     *
     * 	@param actServiceArray
     *
     *	@author Ricardo Martínez <ricardo.martinez@cttc.es>
     *	@date 2022
     */
     /////////////////////////////////////////////////////////////////////////////////////////
    void parsing_json_activeService_array(cJSON* actServiceArray) {
    	DEBUG_PC("");
    	DEBUG_PC("====== PARSING THE JSON CONTENTS OF THE ACTIVE SERVICES =======");
    	
    	for (gint i = 0; i < cJSON_GetArraySize(actServiceArray); i++) {
    		struct activeService_t* actServ = g_malloc0(sizeof(struct activeService_t));
    		if (actServ == NULL) {
    			DEBUG_PC("Memory Allocation Failure");
    			exit(-1);
    		}
    		cJSON* item = cJSON_GetArrayItem(actServiceArray, i);
    		// ServiceId
    		cJSON* serviceIdObj = cJSON_GetObjectItem(item, "serviceId");
    		if (cJSON_IsObject(serviceIdObj)) {
    			parse_json_serviceId(serviceIdObj, &actServ->serviceId);
    		}
    		// Service Type
    		cJSON* serviceTypeObj = cJSON_GetObjectItem(item, "serviceType");
    		if (cJSON_IsNumber(serviceTypeObj))
    		{
    			actServ->service_type = (guint)(serviceTypeObj->valuedouble);
    			print_service_type(actServ->service_type);
    		}
    		// Service Endpoints
    		cJSON* endPointIdsArray = cJSON_GetObjectItem(item, "service_endpoints_ids");
    		if (cJSON_IsArray(endPointIdsArray)) {
    			parse_act_service_endPointsIds_array(endPointIdsArray, actServ);
    		}
    		// Parsing the active service path
    		actServ->activeServPath = NULL;
    		cJSON* actServPathArray = cJSON_GetObjectItem(item, "devices");
    		if (cJSON_IsArray(endPointIdsArray)) {
    			for (gint j = 0; j < cJSON_GetArraySize(actServPathArray); j++) {
    				struct activeServPath_t* actServPath = g_malloc0(sizeof(struct activeServPath_t));
    				if (actServPath == NULL) {
    					DEBUG_PC("Memory Allocation Failure");
    					exit(-1);
    				}
    				cJSON* item2 = cJSON_GetArrayItem(item, j);
    				// Topology Id
    				cJSON* topologyIdObj = cJSON_GetObjectItem(item2, "topology_id");
    				if (cJSON_IsObject(topologyIdObj)) {
    					parse_topology_Id(topologyIdObj, &actServPath->topology_id);
    				}
    				// Device Id
    				cJSON* deviceIdObj = cJSON_GetObjectItem(item2, "device_id");
    				if (cJSON_IsString(deviceIdObj)) {
    					duplicate_string(actServPath->deviceId, deviceIdObj->valuestring);
    				}
    				// EndPointId
    				cJSON* endPointUUIDObj = cJSON_GetObjectItem(item2, "endpoint_uuid");
    				if (cJSON_IsString(endPointUUIDObj)) {
    					duplicate_string(actServPath->endPointId, endPointUUIDObj->valuestring);
    				}
    				// Append element from the Active Service Path (i.e.,topologyId, deviceId and endpointId)
    				actServ->activeServPath = g_list_append(actServ->activeServPath, actServPath);
    			}
    		}
    		// append into the Actice Service List
    		activeServList = g_list_append(activeServList, actServ);
    	}
    	return;
    }
    
    ///////////////////////////////////////////////////////////////////////////////////////
    /**
     * 	@file pathComp_RESTapi.c
     * 	@brief Function used to parse the JSON object/s for the PATH COMP request (i.e. service
     *  requests, device and links)
     * 	
     * 	@param root
     * 	@param source
     *
     *	@author Ricardo Martínez <ricardo.martinez@cttc.es>
     *	@date 2022
     */
    /////////////////////////////////////////////////////////////////////////////////////////
    void parsing_json_obj_pathComp_request(cJSON * root, GIOChannel * source)
    {
    	// Set of services to seek their path and resource selection
    	cJSON* serviceListArray = cJSON_GetObjectItem(root, "serviceList");
    	if (cJSON_IsArray(serviceListArray)) {
    		parsing_json_serviceList_array(serviceListArray);
    	}   
        
    	// Get the deviceList
    	cJSON* deviceListArray = cJSON_GetObjectItem(root, "deviceList");
    	if (cJSON_IsArray(deviceListArray)) {
    		parsing_json_deviceList_array(deviceListArray);
    	}
    
    	// Get the linkList
    	cJSON* linkListArray = cJSON_GetObjectItem(root, "linkList");
    	if (cJSON_IsArray(linkListArray)) {
    		parsing_json_linkList_array(linkListArray);
    
    
    		// In the context information, if solely the list of links are passed for a single direction, 
    		// the reverse direction MUST be created sythetically 
    
    		// LGR: deactivated; link duplication needs to be done smartly with TAPI. done manually in topology by now
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    		//generate_reverse_linkList();
    	}
    
    	// Get the list of active services
    	cJSON* actServiceArray = cJSON_GetObjectItem(root, "activeServList");
    	if (cJSON_IsArray(actServiceArray)) {
    		parsing_json_activeService_array(actServiceArray);
    
    	}
    	return;
    }
    
    ////////////////////////////////////////////////////////////////////////////////////////
    /**
     * 	@file pathComp_RESTapi.c
     * 	@brief Function used parse the JSON object/s 
     * 	
     * 	@param data
     *  @param source
     *
     *	@author Ricardo Martínez <ricardo.martinez@cttc.es>
     *	@date 2022
     */
    /////////////////////////////////////////////////////////////////////////////////////////
    gint parsing_json_obj (guchar *data, GIOChannel *source) {
        cJSON * root = cJSON_Parse((const char *)data);
        char * print = cJSON_Print(root);  
    
    	DEBUG_PC("STARTING PARSING JSON CONTENTS");
    	parsing_json_obj_pathComp_request (root, source);	
    	// Release the root JSON object variable
    	cJSON_free (root);
    	g_free(print);
        return 0;
    }
    
    ////////////////////////////////////////////////////////////////////////////////////////
    /**
     * 	@file pathComp_RESTapi.c
     * 	@brief Create new tcp client connected to PATH COMP
     * 
     * 	@param channel_client, GIOChannel
     *  @param fd
     * 	
     *	@author Ricardo Martínez <ricardo.martinez@cttc.es>
     *	@date 2022
     */
    /////////////////////////////////////////////////////////////////////////////////////////
    struct pathComp_client * RESTapi_client_create (GIOChannel * channel_client, gint fd) {
    	/** check values */
    	g_assert(channel_client != NULL); 
    
    	struct pathComp_client* client = g_malloc0 (sizeof (struct pathComp_client));
    	if (client == NULL )
    	{
    		DEBUG_PC ("Malloc for the client failed");
    		exit(-1);
    	}  
    
    	/** Make client input/output buffer. */
    	client->channel = channel_client;	
    	client->obuf = stream_new(MAXLENGTH);
    	client->ibuf = stream_new(MAXLENGTH);
    	client->fd = fd;
    
    	// Clients connected to the PATH COMP SERVER
    	CLIENT_ID++;
    	client->type = CLIENT_ID;
    
    	//DEBUG_PC ("Client Id: %u is created (%p)", client->type, client);
    	//DEBUG_PC ("Client ibuf: %p || obuf: %p", client->ibuf, client->obuf);
    
    	// Add the tcp client to the list
    	RESTapi_tcp_client_list = g_list_append (RESTapi_tcp_client_list, client);
    	//DEBUG_PC ("Num of TCP Clients: %d", g_list_length (RESTapi_tcp_client_list));
    	return client;
    }
    
    ////////////////////////////////////////////////////////////////////////////////////////
    /**
     * 	@file pathComp_RESTapi.c
     * 	@brief Close the tcp client, removing from the rapi_tcp_client_list
     * 
     * 	@param client
     * 	
     *	@author Ricardo Martínez <ricardo.martinez@cttc.es>
     *	@date 2022
     */
    /////////////////////////////////////////////////////////////////////////////////////////
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    void RESTapi_client_close (struct pathComp_client* client) {
    
    	//DEBUG_PC("Closing the client (Id: %d) %p", client->type, client);
    	//DEBUG_PC("Client ibuf: %p || obuf: %p", client->ibuf, client->obuf);
    	
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	if (client->ibuf != NULL) {
    
    		//DEBUG_PC("Client ibuf: %p", client->ibuf);
    		stream_free(client->ibuf);
    		client->ibuf = NULL;
    	}
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	if (client->obuf != NULL) {
    
    		//DEBUG_PC("Client obuf: %p", client->obuf);
    		stream_free(client->obuf);
    		client->obuf = NULL;
    	}
    	// Remove from the list
    	RESTapi_tcp_client_list = g_list_remove (RESTapi_tcp_client_list, client);
    	//DEBUG_PC ("TCP Client List: %d", g_list_length(RESTapi_tcp_client_list));
    	 
    	g_free (client);
    	client = NULL;	 
    	DEBUG_PC ("client has been removed ...");	 
    	return;
    }
    
    ////////////////////////////////////////////////////////////////////////////////////////
    /**
     * 	@file pathComp_RESTapi.c
     * 	@brief Close operations over the passed tcp channel
     * 
     * 	@param source
     * 	
     *	@author Ricardo Martínez <ricardo.martinez@cttc.es>
     *	@date 2022
     */
    /////////////////////////////////////////////////////////////////////////////////////////
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    void RESTapi_close_operations (GIOChannel * source)	{
    
    	gint fd = g_io_channel_unix_get_fd (source);
    	
    	//DEBUG_PC ("Stop all the operations over the fd: %d", fd);	
    	g_io_channel_flush(source, NULL);
    	GError *error = NULL;    
    	g_io_channel_shutdown (source, TRUE, &error);
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	if(error) {
    
    		DEBUG_PC ("An error occurred ...");
    	}
    	g_io_channel_unref (source);
    	return;	
    }
    
    ////////////////////////////////////////////////////////////////////////////////////////
    /**
     * 	@file pathComp_RESTapi.c
     * 	@brief Remove the client and close operations over the TCP connection
     * 
     * 	@param client
     *  @param source
     *  @param fd
     * 	
     *	@author Ricardo Martínez <ricardo.martinez@cttc.es>
     *	@date 2022
     */
    /////////////////////////////////////////////////////////////////////////////////////////
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    void RESTapi_stop (struct pathComp_client* client, GIOChannel * source, gint fd) {
    
    	
    	DEBUG_PC("Client Socket: %d is Stopped", fd);
    	// remove client
    	RESTapi_client_close(client);
    	// Stop operations over that channel
    	RESTapi_close_operations(source);
    	close (fd);
    	return;
    }
    
    ////////////////////////////////////////////////////////////////////////////////////////
    /**
     * 	@file pathComp_RESTapi.c
     * 	@brief Function used read the different lines ending up in \r\n
     * 	
     * 	@param s
     * 	@param buf
     * 	@param size
     *
     *	@author Ricardo Martínez <ricardo.martinez@cttc.es>
     *	@date 2022
     */
    /////////////////////////////////////////////////////////////////////////////////////////
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    gint RESTapi_get_line (GIOChannel *channel, gchar *buf, gint size) {
    
        gint i = 0;
        //DEBUG_PC ("\n");
        //DEBUG_PC ("----- Read REST API Line(\r\n) ------");
        gint n = 0;
        guchar c = '\0'; // END OF FILE    
        gboolean cr = FALSE;
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
        while (i < size - 1) {
    
    		n = read_channel (channel, &c, 1);		
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    		if (n == -1) {
    
    			//DEBUG_PC ("Close the channel and eliminate the client");
    			return -1;			
    		}	
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    		if (n > 0) {
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    			if (c == '\r') 			{
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    			if ((c == '\n') && (cr == TRUE)) 			{	   
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    		else {
    
    			c = '\n';
    			buf[i] = c;
    			i++;
    			break;
    		}
        }
        buf[i] = '\0';    
        //DEBUG_PC ("Line (size: %d) buf: %s", i, buf);
        return i;
    }  
    
    ////////////////////////////////////////////////////////////////////////////////////////
    /**
     * 	@file pathComp_RESTapi.c
     * 	@brief Function used read the HTTP method
     * 	
     * 	@param buf
     * 	@param j
     *
     *	@author Ricardo Martínez <ricardo.martinez@cttc.es>
     *	@date 2022
     */
    /////////////////////////////////////////////////////////////////////////////////////////
    guint RESTapi_get_method (gchar *buf, gint *j)
    {
    	guint RestApiMethod = 0;
    	gchar method[255];
    	gint i = 0;	
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	while (!ISspace(buf[*j]) && (i < sizeof(method) - 1)) {
    
    		method[i] = buf[*j];
    		i++; 
    		*j = *j + 1;
    	}
    	method[i] = '\0';
    	DEBUG_PC ("REST API METHOD: %s", method);	
    	
    	// Check that the methods are GET, POST or PUT
    	if (strcasecmp((const char *)method, "GET") && strcasecmp((const char *)method, "POST") && 
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    		strcasecmp ((const char *)method, "HTTP/1.1") && strcasecmp ((const char *)method, "PUT")) {
    		DEBUG_PC ("%s is not a method ...", method);
    
    		return RestApiMethod;	
    	}
    	// Method selector
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	if (strncmp ((const char*)method, "GET", 3) == 0) {
    
    		RestApiMethod = REST_API_METHOD_GET;		
    	}
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	else if (strncmp ((const char*)method, "POST", 4) == 0) {
    
    		RestApiMethod = REST_API_METHOD_POST;
    	}	
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	else if (strncmp ((const char *)method, "HTTP/1.1", 8) == 0) {
    
    		RestApiMethod = REST_API_METHOD_HTTP;
    	}
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	else if (strncmp ((const char *)method, "PUT", 3) == 0) {
    
    		RestApiMethod = REST_API_METHOD_PUT;
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	}	
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    ////////////////////////////////////////////////////////////////////////////////////////
    /**
     * 	@file pathComp_RESTapi.c
     * 	@brief Function used to check whether it is a supported method, and return the associated numerical id
     *
     * 	@param method
     *
     *	@author Ricardo Martínez <ricardo.martinez@cttc.es>
     *	@date 2022
     */
     /////////////////////////////////////////////////////////////////////////////////////////
    guint is_rest_api_method(char *method) {
    	guint RestApiMethod = 0;
    	if (strcasecmp((const char*)method, "GET") && strcasecmp((const char*)method, "POST") &&
    		strcasecmp((const char*)method, "HTTP/1.1") && strcasecmp((const char*)method, "PUT")) {
    		DEBUG_PC("The method: %s is not currently supported ...", method);
    		return RestApiMethod;
    	}
    	// Method selector
    	if (strncmp((const char*)method, "GET", 3) == 0) {
    		RestApiMethod = REST_API_METHOD_GET;
    	}
    	else if (strncmp((const char*)method, "POST", 4) == 0) {
    		RestApiMethod = REST_API_METHOD_POST;
    	}
    	else if (strncmp((const char*)method, "HTTP/1.1", 8) == 0) {
    		RestApiMethod = REST_API_METHOD_HTTP;
    	}
    	else if (strncmp((const char*)method, "PUT", 3) == 0) {
    		RestApiMethod = REST_API_METHOD_PUT;
    	}
    	return RestApiMethod;
    }
    
    
    ////////////////////////////////////////////////////////////////////////////////////////
    /**
     * 	@file pathComp_RESTapi.c
     * 	@brief Function used read the url
     * 	
     * 	@param buf
     * 	@param j
     *  @param url
     *
     *	@author Ricardo Martínez <ricardo.martinez@cttc.es>
     *	@date 2022
     */
    /////////////////////////////////////////////////////////////////////////////////////////
    gint get_url (gchar *buf, gint *j, gchar *url)
    {
    	// Skip space char
    	while (ISspace(buf[*j]) && (*j < strlen(buf))) {
    		*j = *j + 1;
    	}
    	
    	//DEBUG_PC ("buf[%d]: %c", *j, buf[*j]);
    	int result = isspace (buf[*j]);	
    	*buf = *buf + *j;
    	gint numChar = 0;
    	gint initChar = *j;
    	result = 0;
    	while (result == 0)	{
    		*j = *j + 1;
    		result = isspace (buf[*j]);
    		numChar++;
    	}
    	//DEBUG_PC ("numChar: %d", numChar);
    	memcpy (url, buf + initChar, numChar);
    	url[numChar] = '\0';
    	//DEBUG_PC ("url: %s", url);
    	return numChar;
    }
    
    ////////////////////////////////////////////////////////////////////////////////////////
    /**
     * 	@file pathComp_RESTapi.c
     * 	@brief Function used read the version
     * 	
     * 	@param buf
     * 	@param j
     *  @param version
     *
     *	@author Ricardo Martínez <ricardo.martinez@cttc.es>
     *	@date 2022
     */
    /////////////////////////////////////////////////////////////////////////////////////////
    gint get_version (gchar *buf, gint *j, gchar *version) {
    	// Skip space char
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	while (ISspace(buf[*j]) && (*j < strlen(buf))) {
    
    		*j = *j + 1;
    	}	
    	//DEBUG_PC ("buf[%d]: %c", *j, buf[*j]);
    	int result = isspace (buf[*j]);	
    	*buf = *buf + *j;
    	gint numChar = 0;
    	gint initChar = *j;
    	result = 0;
    	while (result == 0)	{
    		*j = *j + 1;
    		result = isspace (buf[*j]);
    		numChar++;
    	}
    	//DEBUG_PC ("numChar: %d", numChar);
    	memcpy (version, buf + initChar, numChar);
    	version[numChar] = '\0';
    	//DEBUG_PC ("version: %s", version);	
    	return numChar;
    }
    
    ////////////////////////////////////////////////////////////////////////////////////////
    /**
     * 	@file pathComp_RESTapi.c
     * 	@brief Function used to trigger the route computation for the network connectivity service
     *  List and retrieve the result
     * 	
     * 	@param compRouteList
     * 	@param raId
     *
     *	@author Ricardo Martínez <ricardo.martinez@cttc.es>
     *	@date 2022
     */
    /////////////////////////////////////////////////////////////////////////////////////////
    gint triggering_routeComp (struct compRouteOutputList_t *compRouteList, gchar *algId) {
    	g_assert (compRouteList);	
    	gint httpCode = HTTP_RETURN_CODE_OK;
    	DEBUG_PC("Requested Algorithm: %s", algId);
    	//////////////////// Algorithm Selector (RAId)//////////////////////////////////////	
    
    	// KSP algorithm
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	if (strncmp ((const char*)algId, "KSP", 3) == 0) {
    
    		DEBUG_PC ("Alg Id: KSP");
    		httpCode = pathComp_ksp_alg(compRouteList);
    	}
    
    	// simple SP algorithm
    	else if (strncmp((const char*)algId, "SP", 2) == 0) {
    		DEBUG_PC("Alg Id: SP");
    		httpCode = pathComp_sp_alg(compRouteList);
    	}
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	// energy-aware routing
    	else if (strncmp((const char*)algId, "EAR", 3) == 0) {
    		DEBUG_PC("Alg Id: Energy Aware Routing, EAR");
    		httpCode = pathComp_ear_alg(compRouteList);
    
    	}
    	return httpCode;
    }
    
    ////////////////////////////////////////////////////////////////////////////////////////
    /**
     * 	@file pathComp_RESTapi.c
     * 	@brief Function used to process the REST API commands
     * 	
     * 	@param source
     * 	@param cond
     * 	@param data
     *
     *	@author Ricardo Martínez <ricardo.martinez@cttc.es>
     *	@date 2022
     */
    /////////////////////////////////////////////////////////////////////////////////////////
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    gboolean RESTapi_activity(GIOChannel *source, GIOCondition cond, gpointer data) {  
    
    	/** some checks */
    	g_assert(source != NULL);
    	g_assert(data != NULL);	
    	
    	gchar buf[1024];
    	gchar version[255];
    	gchar http_result[255];
    	gint body_length = 0;	
    
    	struct pathComp_client *client = (struct pathComp_client*)(data);
    	DEBUG_PC (" ************************************************************************** ");    
    	DEBUG_PC ("                      REST API ACTIVITY Triggered ");
    	DEBUG_PC (" ************************************************************************** ");   
    
    	gint fd = g_io_channel_unix_get_fd (source);
    	DEBUG_PC ("fd: %d, cond: %d", fd, cond);
    
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	if (cond != G_IO_IN) {
    
    		DEBUG_PC ("Something happening with the channel and fd ... (cond: %d)", cond);
    		RESTapi_stop(client, source, fd);
    		return FALSE;
    	}	
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	// Clear input buffer
    
    	stream_reset (client->ibuf);
    
    	// get line
    	gint nbytes = RESTapi_get_line (source, buf, sizeof (buf));
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	if (nbytes == -1) {
    
    		DEBUG_PC ("nbytes -1 ... CLOSE CLIENT FD and eliminate CLIENT");						
    		RESTapi_stop(client, source, fd);
    		return FALSE;						
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	}	
    
    	if ((buf[0] == '\n') && (nbytes  == 1))
    	{
    		//DEBUG_PC (" -- buf[0] = newline --");
    		RESTapi_stop(client, source, fd);
    		return FALSE;
    	}
    	
    	gint i = 0, j = 0;
    
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	while (1) {
    		DEBUG_PC("%s", buf);
    		char word[255];		
    		while (!ISspace(buf[j]) && (i < sizeof(word) - 1)) {
    			word[i] = buf[j]; i++; j++;
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    		word[i] = '\0';
    		// Check if word is bound to a Method, i.e., POST, GET, HTTP/1.1.
    		guint method = is_rest_api_method(word);
    		if (method == 0) {
    			 // ignore other REST fields i.e., Host:, User-Agent:, Accept: ....			
    			break;
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    		// word is bound to a known / supported REST Method
    		else {
    			gchar url[255];
    			i = get_url(buf, &j, url);
    			url[i] = '\0';
    			// GET - used for checking status of pathComp ... used url /pathComp/api/v1/health
    			if (method == REST_API_METHOD_GET) {
    				if (strncmp((const char*)url, "/health", 7) != 0) {
    					DEBUG_PC("unknown url [%s] for GET method -- Heatlh function", url);
    					RESTapi_stop(client, source, fd);
    					exit(-1);
    				}
    				else {
    					DEBUG_PC("Sending API Response OK to health requests");
    					rapi_response_ok(source, HTTP_RETURN_CODE_OK, NULL);
    					return TRUE;
    				}
    			}
    			// for method POST, PUT check that the url is "/pathComp"
    			if (method == REST_API_METHOD_POST) {
    				if (strncmp((const char*)url, "/pathComp/api/v1/compRoute", 26) != 0) {
    					DEBUG_PC("Unknown url: %s", url);
    					RESTapi_stop(client, source, fd);
    					exit(-1);
    				}
    			}
    			// get the version	
    			i = get_version(buf, &j, version);
    			version[i] = '\0';
    			break;
    
    	}
    	// Assume HTTP/1.1, then there is Host Header
    	memset(buf, '\0', sizeof(buf));        
    	nbytes = RESTapi_get_line(source, buf, sizeof (buf));
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	if (nbytes == -1) {
    
    		DEBUG_PC ("nbytes -1 ... then close the fd and eliminate associated client");			
    		RESTapi_stop(client, source, fd);
    		return FALSE;					
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	}	
    
    	
    	// Headers --- The Header Fields ends up with a void line (i.e., \r\n)
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	while ((nbytes > 0) && (strcmp ("\r\n", (const char *)buf) != 0)) {	
    
    		/* read & discard headers */
    		memset(buf, '\0', sizeof(buf));  
    		nbytes = RESTapi_get_line (source, buf, sizeof (buf));
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    		if (nbytes == -1) {
    
    			DEBUG_PC ("nbytes -1 ... then close the fd and eliminate associated client");	
    			RESTapi_stop(client, source, fd);
    			return FALSE;
    		}
    		//DEBUG_PC ("Header: %s", buf);	  
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    		if (strncmp ((const char *)buf, "Content-Length:", 15) == 0) {
    
    			//DEBUG_PC ("Header Content-Length Found");
    			gchar str[20];
    	  
    			gint i = 15, k = 0;  // "Content-Length:" We skip the first 16 characters to directly retrieve the length in bytes of the Body of Request
    			gchar contentLength[255];
    			memset (contentLength, '\0', sizeof (contentLength));			
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    			while (buf[i] != '\r') {
    
    				//DEBUG_PC ("%c", buf[i]);
    				str[k] = buf[i];
    				k++, i++;
    			}
    			str[k] = '\0';			
    			j = 0, i = 0;
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    			while (ISspace(str[j]) && (j < strlen(str))) {
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    			while (j < strlen(str)) {
    
    				contentLength[i] = str[j];
    				i++; j++;
    			}
    			contentLength[i] = '\0';			
    			body_length = atoi (contentLength);
    			//DEBUG_PC ("Body length: %d (%s) in Bytes", body_length, contentLength);	      
    		}	  
    	}
    	//DEBUG_PC("Read Entire HTTP Header");
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	if (body_length == 0) {
    
    		DEBUG_PC ("--- NO REST API Body length (length = %d) ---", body_length);
    		return TRUE;
    	}       
    	//////////////////////////////////////////////////////////////////////////////////////////////////////////////
    	// Processing Body of the Request
    	/////////////////////////////////////////////////////////////////////////////////////////////////////////////
    	//DEBUG_PC ("REST API Request - Body -");
    	nbytes = read_channel (source, (guchar *)(client->ibuf->data + client->ibuf->putp), body_length);
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	if ((nbytes < 0) && (body_length > 0)) 	{
    
    		DEBUG_PC ("nbytes: %d; body_length: %d", nbytes, body_length);
    		exit (-1);
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	}	
    
    	client->ibuf->putp += nbytes;
    	client->ibuf->endp += nbytes;		
    	///////////////////////////////////////////////////////////////////////////////////////////////////////////////
    	// Parsing the contents of the Request
    	///////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	// build the device list	
    	deviceList = NULL;
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	linkList = NULL;
    
    	// Create the network connectivity service list
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	serviceList = NULL;
    	// Create the active service List
    	activeServList = NULL;
    
    	
    	// Process the json contents and store relevant information at Device, Link,
    	// and network connectivity service
    	gint ret = parsing_json_obj (client->ibuf->data, source);	
    	if (ret == -1) 	{
    		DEBUG_PC ("Something wrong with the JSON Objects ... ");		
    		RESTapi_stop(client, source, fd);
    		return FALSE;
    	}	
    	
    	//////////////////////////////////////////////////////////////////////////////////////////////////////////////		
    	// Trigger the path computation	
    	//////////////////////////////////////////////////////////////////////////////////////////////////////////////
    	//DEBUG_PC ("Triggering the computation");
    	struct compRouteOutputList_t *compRouteOutputList = create_route_list ();
    	gint httpCode = triggering_routeComp (compRouteOutputList, algId);	
    
    	// Send the response to the REST  API Client
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	if (httpCode != HTTP_RETURN_CODE_OK) {            
    
    		DEBUG_PC ("HTTP CODE: %d -- NO OK", httpCode);
    		rapi_response (source, httpCode);
    	}
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	else {
    
    		DEBUG_PC ("HTTP CODE: %d -- OK", httpCode);
    		rapi_response_ok (source, httpCode, compRouteOutputList);            
    	}
    	
    	// Release the variables		
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	g_free (compRouteOutputList);	
    	g_list_free_full(g_steal_pointer(&linkList), (GDestroyNotify)destroy_link);
    	g_list_free_full(g_steal_pointer(&deviceList), (GDestroyNotify)destroy_device);
    	g_list_free_full(g_steal_pointer(&serviceList), (GDestroyNotify)destroy_requested_service);
    	g_list_free_full(g_steal_pointer(&activeServList), (GDestroyNotify)destroy_active_service);
    
    	return TRUE;  
    }
    
    ////////////////////////////////////////////////////////////////////////////////////////
    /**
     * 	@file pathComp_RESTapi.c
     * 	@brief Function used to accept a new connection and add the client to list of clients
     * 
     * 	@param source, GIOChannel
     * 	@param cond, GIOCondition
     * 	@param data, gpointer
     *
     *	@author Ricardo Martínez <ricardo.martinez@cttc.es>
     *	@date 2022
     */
    /////////////////////////////////////////////////////////////////////////////////////////
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    gboolean RESTapi_tcp_new_connection(GIOChannel *source, GIOCondition cond, gpointer data) {
    
    	DEBUG_PC (" ****** New TCP Connection (REST API) ******");
    	/** get size of client_addre structure */
    	struct sockaddr_in client_addr;
    	socklen_t client = sizeof(client_addr);
    	
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	if ((cond == G_IO_HUP) || (cond == G_IO_ERR) || (G_IO_NVAL)) {
    
    		//DEBUG_PC ("Something happening with the channel and fd ... cond: %d", cond);		
    		// Find the associated client (by the fd) and remove from PATH COMP client list. 
    		// Stop all the operations over that PATH COMP client bound channel
    		struct pathComp_client *pathComp_client = NULL;
    		gint fd = g_io_channel_unix_get_fd (source);
    		GList *found = g_list_find_custom (RESTapi_tcp_client_list, &fd, find_rl_client_by_fd);
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    		if (found != NULL) 	{