diff options
author | Brant Thomsen <brant.thomsen@harman.com> | 2017-06-09 12:49:03 -0600 |
---|---|---|
committer | Brant Thomsen <brant.thomsen@harman.com> | 2017-06-09 12:49:03 -0600 |
commit | 87521a71f8fa9323423dba456096618c01fc8f86 (patch) | |
tree | 3a5df17a5c61921e6915efc6cc4be4effde2ca11 /daemons | |
parent | 2b3fd1772c67d701e9fdb10fe95aea80887c45ea (diff) | |
download | Open-AVB-87521a71f8fa9323423dba456096618c01fc8f86.tar.gz |
shaper daemon
Added the Harman shaper daemon code under the OpenAvnu daemons folder.
Code uses the same license type as the AVTP Pipeline contribution.
Diffstat (limited to 'daemons')
-rw-r--r-- | daemons/shaper/LICENSE | 25 | ||||
-rw-r--r-- | daemons/shaper/Makefile | 37 | ||||
-rw-r--r-- | daemons/shaper/src/platform.h | 74 | ||||
-rw-r--r-- | daemons/shaper/src/shaper_daemon.c | 814 | ||||
-rw-r--r-- | daemons/shaper/src/shaper_helper_linux.h | 182 | ||||
-rw-r--r-- | daemons/shaper/src/shaper_log.h | 261 | ||||
-rw-r--r-- | daemons/shaper/src/shaper_log_linux.c | 445 | ||||
-rw-r--r-- | daemons/shaper/src/shaper_log_queue.c | 200 | ||||
-rw-r--r-- | daemons/shaper/src/shaper_log_queue.h | 78 |
9 files changed, 2116 insertions, 0 deletions
diff --git a/daemons/shaper/LICENSE b/daemons/shaper/LICENSE new file mode 100644 index 00000000..9a67d06a --- /dev/null +++ b/daemons/shaper/LICENSE @@ -0,0 +1,25 @@ +/************************************************************************************************************* +Copyright (c) 2016-2017, Harman International Industries, Incorporated +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*************************************************************************************************************/ + diff --git a/daemons/shaper/Makefile b/daemons/shaper/Makefile new file mode 100644 index 00000000..13e4b037 --- /dev/null +++ b/daemons/shaper/Makefile @@ -0,0 +1,37 @@ +CC ?= gcc +OPT = -O2 -g +CFLAGS = $(OPT) -Wall -Wextra +INCFLAGS = +LDLIBS = -lm -pthread + +SRC_DIR = src +OUT_O_DIR = build + +all: shaper_daemon + +shaper_daemon: \ + $(OUT_O_DIR)/shaper_daemon.o \ + $(OUT_O_DIR)/shaper_log_queue.o \ + $(OUT_O_DIR)/shaper_log_linux.o + +$(OUT_O_DIR)/shaper_daemon.o: $(SRC_DIR)/shaper_daemon.c \ + $(SRC_DIR)/shaper_log.h + @mkdir -p $(@D) + $(CC) $(CFLAGS) $(INCFLAGS) -c $(SRC_DIR)/shaper_daemon.c -o $(OUT_O_DIR)/shaper_daemon.o + +$(OUT_O_DIR)/shaper_log_queue.o: $(SRC_DIR)/shaper_log_queue.c \ + $(SRC_DIR)/shaper_log.h $(SRC_DIR)/shaper_log_queue.h + @mkdir -p $(@D) + $(CC) $(CFLAGS) $(INCFLAGS) -c $(SRC_DIR)/shaper_log_queue.c -o $(OUT_O_DIR)/shaper_log_queue.o + +$(OUT_O_DIR)/shaper_log_linux.o: $(SRC_DIR)/shaper_log_linux.c \ + $(SRC_DIR)/platform.h $(SRC_DIR)/shaper_log.h $(SRC_DIR)/shaper_log_queue.h $(SRC_DIR)/shaper_helper_linux.h + @mkdir -p $(@D) + $(CC) $(CFLAGS) $(INCFLAGS) -c $(SRC_DIR)/shaper_log_linux.c -o $(OUT_O_DIR)/shaper_log_linux.o + +%: $(OUT_O_DIR)/%.o + $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ + +clean: + $(RM) shaper_daemon + $(RM) -r $(OUT_O_DIR) diff --git a/daemons/shaper/src/platform.h b/daemons/shaper/src/platform.h new file mode 100644 index 00000000..3691d584 --- /dev/null +++ b/daemons/shaper/src/platform.h @@ -0,0 +1,74 @@ +/************************************************************************************************************* +Copyright (c) 2016-2017, Harman International Industries, Incorporated +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*************************************************************************************************************/ + +#ifndef MAAP_PLATFORM_H +#define MAAP_PLATFORM_H + +#if defined(__linux__) + +#include <endian.h> +#include <time.h> + +#define OS_TIME_TYPE struct timespec + +#elif defined(__APPLE__) + +#include <libkern/OSByteOrder.h> +#include <sys/time.h> + +#define htobe16(x) OSSwapHostToBigInt16(x) +#define be16toh(x) OSSwapBigToHostInt16(x) +#define htobe64(x) OSSwapHostToBigInt64(x) +#define be64toh(x) OSSwapBigToHostInt64(x) + +#define ETH_ALEN 6 + +#define OS_TIME_TYPE struct timeval + +#elif defined(_WIN32) + +#include <Winsock2.h> + +#define htobe16(x) htons(x) +#define be16toh(x) ntohs(x) +#define htobe64(x) ((htonl(1) == 1) ? x : ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32)) +#define be64toh(x) ((ntohl(1) == 1) ? x : ((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32)) + +#define OS_TIME_TYPE struct timeval + +#else + +#error Please create the platform support definitions for this platform + +#endif + + +#define HTOBE16(x) htobe16(x) +#define BE16TOH(x) be16toh(x) +#define HTOBE64(x) htobe64(x) +#define BE64TOH(x) be64toh(x) + + +#endif diff --git a/daemons/shaper/src/shaper_daemon.c b/daemons/shaper/src/shaper_daemon.c new file mode 100644 index 00000000..921e140c --- /dev/null +++ b/daemons/shaper/src/shaper_daemon.c @@ -0,0 +1,814 @@ +/************************************************************************************************************* +Copyright (c) 2016-2017, Harman International Industries, Incorporated +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*************************************************************************************************************/ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> +#include <ctype.h> +#include <net/if.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <netinet/in.h> +#include <errno.h> +#include <fcntl.h> + +#define SHAPER_LOG_COMPONENT "Main" +#include "shaper_log.h" + +#define STREAMDA_LENGTH 18 +#define SHAPER_PORT 15365 /* Unassigned at https://www.iana.org/assignments/port-numbers */ +#define MAX_CLIENT_CONNECTIONS 10 +#define USER_COMMAND_PROMPT "\nEnter the command: " + +typedef struct cmd_ip +{ + int reserve_bw; + int unreserve_bw; + char interface[IFNAMSIZ]; + int measurement_interval;//usec + int max_frame_size; + int max_frame_interval; + char stream_da[STREAMDA_LENGTH]; + int delete_qdisc; + int quit; +}cmd_ip; + +typedef struct stream_da +{ + char dest_addr[STREAMDA_LENGTH]; + int bandwidth; + char class_id[5]; + int filter_handle; + struct stream_da *next; +}stream_da; + +stream_da *head = NULL; +int sr_classa=0, sr_classb=0; +int classa_48=0, classa_44=0, classb_48=0; +int classa_bw_48=0, classa_bw_44=0, classb_bw_48=0; +int daemonize=0,c=0; +int filterhandle_classa=1,filterhandle_classb=20; +char classid_a_48[]="2:10"; +char classid_a_44[]="2:20"; +char classid_b_48[]="3:30"; +char interface[IFNAMSIZ] = {0}; +int bandwidth = 0; +int classa_parent = 2, classb_parent=3; + +void log_client_error_message(int sockfd, const char *fmt, ...) +{ + static char error_msg[200], combined_error_msg[250]; + va_list args; + + /* Get the error message. */ + va_start(args, fmt); + vsprintf(error_msg, fmt, args); + va_end(args); + + if (sockfd < 0) + { + /* Received from stdin. Just log this error. */ + SHAPER_LOG_ERROR(error_msg); + } + else + { + /* Log this as a remote client error. */ + sprintf(combined_error_msg, "Client %d: %s", sockfd, error_msg); + SHAPER_LOG_ERROR(combined_error_msg); + + /* Send the error message to the client. */ + sprintf(combined_error_msg, "ERROR: %s\n", error_msg); + send(sockfd, combined_error_msg, strlen(combined_error_msg), 0); + } +} + +int is_empty() +{ + return head == NULL; +} + +void insert_stream_da(int sockfd, char dest_addr[], int bandwidth, char class_id[], int filter_handle) +{ + stream_da *node = (stream_da *)malloc(sizeof(stream_da)); + if (node == NULL) + { + log_client_error_message(sockfd, "Unable to allocate memory. Exiting program"); + shaperLogExit(); + exit(1); + } + strcpy(node->dest_addr,dest_addr); + node->bandwidth = bandwidth; + strcpy(node->class_id,class_id); + node->filter_handle=filter_handle; + node->next = NULL; + if (is_empty()) + { + head = node; + } + else + { + stream_da *current = head; + while (current->next != NULL) + { + current = current->next; + } + current->next = node; + } +} + +int check_stream_da(int sockfd, char dest_addr[]) +{ + stream_da *current = head; + while (current != NULL) + { + if (!strcmp(current->dest_addr, dest_addr)) + { + log_client_error_message(sockfd, "Stream DA already present"); + return 1; + } + current = current->next; + } + return 0; +} + +stream_da* get_stream_da(int sockfd, char dest_addr[]) +{ + stream_da *current = head; + while (current != NULL) + { + if (!strcmp(current->dest_addr, dest_addr)) + { + + return current; + } + current = current->next; + } + log_client_error_message(sockfd, "Unknown Stream DA"); + return NULL; +} + +void remove_stream_da(int sockfd, char dest_addr[]) +{ + stream_da *current = head; + (void) sockfd; + + if (current != NULL && !strcmp(current->dest_addr, dest_addr)) + { + head = current->next; + free(current); + return; + } + + while (current->next != NULL) + { + if (!strcmp(current->next->dest_addr, dest_addr)) + { + stream_da *temp = current->next; + current->next = current->next->next; + free(temp); + return; + } + current = current->next; + } +} + +void delete_streamda_list() +{ + stream_da *current = head; + stream_da *next = NULL; + while (current != NULL) + { + next = current->next; + free(current); + current = next; + } + head = NULL; +} + +void usage (int sockfd) +{ + const char *usage = "Usage:\n" + " -r Reserve Bandwidth\n" + " -u Unreserve Bandwidth\n" + " -i Interface\n" + " -s Measurement interval (in microseconds)\n" + " -b Maximum frame size (in bytes)\n" + " -f Maximum frame interval\n" + " -a Stream Destination Address\n" + " -d Delete qdisc\n" + " -q Quit Application\n" + "Reserving Bandwidth Example:\n" + " -ri eth2 -s 125 -b 74 -f 1 -a ff:ff:ff:ff:ff:11\n" + "Unreserving Bandwidth Example:\n" + " -ua ff:ff:ff:ff:ff:11\n" + "Quit Example:\n" + " -q\n" + "Delete qdisc Example:\n" + " -d\n"; + if (sockfd < 0) + { + printf("%s",usage); + } + else + { + send(sockfd, usage, strlen(usage),0); + } + +} + +cmd_ip parse_cmd(char command[]) +{ + cmd_ip inputs={0}; + int i=0; + char temp[100]; + while(command[i++] != '\0') + { + + if (command[i] == 'r') + { + inputs.reserve_bw=1; + i++; + } + + if (command[i] == 'u') + { + inputs.unreserve_bw=1; + i++; + } + + if (command[i] == 'i') + { + int k=0; + i = i+2; + while (command[i] != ' ' && k < IFNAMSIZ-1) + { + inputs.interface[k] = command[i]; + k++;i++; + } + inputs.interface[k] = '\0'; + } + + if (command[i] == 's') + { + int k=0; + i = i+2; + while (command[i] != ' ' && k < (int) sizeof(temp)-1) + { + temp[k] = command[i]; + k++;i++; + } + temp[k] = '\0'; + inputs.measurement_interval = atoi(temp); + } + + if (command[i] == 'b') + { + int k=0; + i = i+2; + while (command[i] != ' ' && k < (int) sizeof(temp)-1) + { + temp[k] = command[i]; + k++;i++; + } + temp[k] = '\0'; + inputs.max_frame_size = atoi(temp); + } + + if (command[i] == 'f') + { + int k=0; + i = i+2; + while (command[i] != ' ' && k < (int) sizeof(temp)-1) + { + temp[k] = command[i]; + k++;i++; + } + temp[k] = '\0'; + inputs.max_frame_interval = atoi(temp); + } + + if (command[i] == 'a') + { + int k=0; + i = i+2; + while (command[i] != ' ' && k < STREAMDA_LENGTH-1) + { + inputs.stream_da[k] = command[i]; + k++;i++; + } + inputs.stream_da[k] = '\0'; + } + + if (command[i] == 'd') + { + inputs.delete_qdisc=1; + i++; + } + + if (command[i] == 'q') + { + inputs.quit = 1; + i++; + } + } + return inputs; +} + +void tc_class_command(int sockfd, char command[],char class_id[],char interface[], int bandwidth, int cburst) +{ + char tc_command[1000]={0}; + sprintf(tc_command, "tc class %s dev %s classid %s htb rate %dkbit cburst %d",command, interface, class_id, bandwidth, cburst); + if (system(tc_command) < 0) + { + log_client_error_message(sockfd, "command(\"%s\") failed", tc_command); + } +} + +void add_filter(int sockfd, char interface[], int parent, int filter_handle, char class_id[], char dest_addr[]) +{ + char tc_command[1000]={0}; + sprintf(tc_command, "tc filter add dev %s prio 1 handle 800::%d parent %d: u32 classid %s match ether dst %s", interface,filter_handle,parent,class_id,dest_addr ); + if (system(tc_command) < 0) + { + log_client_error_message(sockfd, "command(\"%s\") failed", tc_command); + } +} + +// Returns 1 if successful, -1 on an error, or 0 if exit requested. +int process_command(int sockfd, char command[]) +{ + cmd_ip input = parse_cmd(command); + char tc_command[1000]={0}; + int maxburst = 0; + + if (input.reserve_bw && input.unreserve_bw) + { + log_client_error_message(sockfd, "Cannot reserve and unreserve bandwidth at the same time"); + usage(sockfd); + return -1; + } + + + if (input.reserve_bw) + { + if (input.max_frame_size == 0 || input.measurement_interval == 0 || input.max_frame_interval == 0) + { + log_client_error_message(sockfd, "max_frame_size, measurement_interval and max_frame_interval are mandatory inputs"); + usage(sockfd); + return -1; + } + } + if (input.unreserve_bw) + { + if (input.stream_da == 0) + { + log_client_error_message(sockfd, "Stream Destination Address is required to unreserve bandwidth"); + usage(sockfd); + return -1; + } + } + if ((input.quit==1 || input.delete_qdisc==1) &&(input.reserve_bw==1 || input.unreserve_bw==1)) + { + log_client_error_message(sockfd, "Quit or Delete cannot be used with other commands"); + usage(sockfd); + return -1; + } + + if (input.quit == 1 || input.delete_qdisc == 1) + { + if (sr_classa != 0 || sr_classb != 0) + { + //delete all the Stream DAs in list + delete_streamda_list(); + if (strlen(interface)!=0) + { + //delete qdisc + sprintf(tc_command, "tc qdisc del dev %s root handle 1:", interface); + if (system(tc_command) < 0) + { + log_client_error_message(sockfd, "command(\"%s\") failed", tc_command); + } + } + sr_classa = sr_classb = classa_48 = classa_44 = classb_48 = classa_bw_48 = classa_bw_44 = classb_bw_48 = 0; + } + + if (input.quit == 1) + { + return 0; + } + } + + if (sr_classa == 0 && sr_classb == 0) + { + //Initializing qdisc + if (strlen(input.interface)==0) + { + if (input.unreserve_bw || input.reserve_bw) + { + log_client_error_message(sockfd, "Interface is mandatory for the first command"); + } + usage(sockfd); + return -1; + } + sprintf(tc_command, "tc qdisc add dev %s root handle 1: mqprio num_tc 4 map 0 1 2 3 2 0 0 1 1 1 1 1 3 3 3 3 queues 1@0 1@1 1@2 1@3 hw 0", input.interface); + if (system(tc_command) < 0) + { + log_client_error_message(sockfd, "command(\"%s\") failed", tc_command); + return -1; + } + strcpy(interface,input.interface); + } + + if (input.unreserve_bw || input.reserve_bw) + { + bandwidth = ceil(((1/(input.measurement_interval*pow(10,-6))) * (input.max_frame_size*8) * input.max_frame_interval)/1000); + maxburst = input.max_frame_size*input.max_frame_interval*2; + } + + if (input.reserve_bw == 1) + { + if (check_stream_da(sockfd, input.stream_da)) + { + return 1; + } + if (input.measurement_interval == 125 || input.measurement_interval == 136) + { + if (sr_classa == 0) + { + sr_classa=1; + //Create qdisc for Class A traffic + sprintf(tc_command, "tc qdisc add dev %s handle %d: parent 1:5 htb", interface, classa_parent); + if (system(tc_command) < 0) + { + log_client_error_message(sockfd, "command(\"%s\") failed", tc_command); + return -1; + } + } + + if (input.measurement_interval == 125) + { + classa_bw_48 = classa_bw_48 + bandwidth; + if (classa_48 == 0) + { + classa_48 = 1; + tc_class_command(sockfd, "add",classid_a_48,interface,classa_bw_48, maxburst); + } + else + { + tc_class_command(sockfd, "change",classid_a_48, interface,classa_bw_48, maxburst); + } + + add_filter(sockfd, interface, classa_parent, filterhandle_classa, classid_a_48, input.stream_da ); + insert_stream_da(sockfd, input.stream_da, bandwidth, classid_a_48, filterhandle_classa ); + filterhandle_classa++; + } + else + { + classa_bw_44 = classa_bw_44 + bandwidth; + if (classa_44 == 0) + { + classa_44 = 1; + tc_class_command(sockfd, "add",classid_a_44,interface,classa_bw_44, maxburst); + } + else + { + tc_class_command(sockfd, "change",classid_a_44, interface,classa_bw_44, maxburst); + } + + add_filter(sockfd, interface, classa_parent, filterhandle_classa, classid_a_44, input.stream_da ); + insert_stream_da(sockfd, input.stream_da, bandwidth, classid_a_44, filterhandle_classa); + filterhandle_classa++; + } + } + else if (input.measurement_interval == 250) + { + if (sr_classb == 0) + { + sr_classb = 1; + //Create qdisc for Class B traffic + sprintf(tc_command, "tc qdisc add dev %s handle %d: parent 1:6 htb", interface, classb_parent); + if (system(tc_command) < 0) + { + log_client_error_message(sockfd, "command(\"%s\") failed", tc_command); + return -1; + } + } + + classb_bw_48 = classb_bw_48 + bandwidth; + if (classb_48 == 0) + { + classb_48 = 1; + tc_class_command(sockfd, "add",classid_b_48,interface,classb_bw_48, maxburst); + } + else + { + tc_class_command(sockfd, "change",classid_b_48, interface,classb_bw_48, maxburst); + } + add_filter(sockfd, interface, classb_parent, filterhandle_classb, classid_b_48, input.stream_da ); + insert_stream_da(sockfd, input.stream_da, bandwidth, classid_b_48, filterhandle_classb); + filterhandle_classb++; + } + else + { + log_client_error_message(sockfd, "Measurement Interval doesn't match that of Class A(125 or 136) or Class B(250) traffic. Enter a valid measurement interval"); + return -1; + } + } + else if (input.unreserve_bw==1) + { + stream_da *remove_stream = get_stream_da(sockfd, input.stream_da); + if (remove_stream != NULL) + { + int class_bw = 0; + if (!strcmp(remove_stream->class_id,classid_a_48)) + { + classa_bw_48 = classa_bw_48 - remove_stream->bandwidth; + class_bw = classa_bw_48; + } + else if (!strcmp(remove_stream->class_id,classid_a_44)) + { + classa_bw_44 = classa_bw_44 - remove_stream->bandwidth; + class_bw = classa_bw_44; + } + else + { + classb_bw_48 = classb_bw_48 - remove_stream->bandwidth; + class_bw = classb_bw_48; + } + if (class_bw == 0) + { + class_bw=1; + } + tc_class_command(sockfd, "change",remove_stream->class_id, interface,class_bw, maxburst); + char parent[3]={0}; + strncpy(parent,remove_stream->class_id,2); + sprintf(tc_command, "tc filter del dev %s parent %s handle 800::%d prio 1 protocol all u32",interface,parent,remove_stream->filter_handle); + if (system(tc_command) < 0) + { + log_client_error_message(sockfd, "command(\"%s\") failed", tc_command); + return -1; + } + remove_stream_da(sockfd, remove_stream->dest_addr); + } + } + + return 1; +} + +int init_socket() +{ + int socketfd = 0; + struct sockaddr_in serv_addr; + int yes=1; + if ((socketfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ) + { + SHAPER_LOGF_ERROR("Could not open socket %d. Error %d (%s)", socketfd, errno, strerror(errno)); + return -1; + } + if (fcntl(socketfd, F_SETFL, O_NONBLOCK) < 0) + { + SHAPER_LOGF_ERROR("Could not set the socket to non-blocking. Error %d (%s)", errno, strerror(errno)); + close(socketfd); + return -1; + } + + + memset(&serv_addr, '0', sizeof(serv_addr)); + + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + serv_addr.sin_port = htons(SHAPER_PORT); + setsockopt(socketfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)); + + if (bind(socketfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr))<0) + { + SHAPER_LOGF_ERROR("bind() error %d (%s)", errno, strerror(errno)); + return -1; + } + if (listen(socketfd, 10)<0) + { + SHAPER_LOGF_ERROR("listen() error %d (%s)", errno, strerror(errno)); + return -1; + } + + return socketfd; + +} + +int main (int argc, char *argv[]) +{ + char command[100]; + int socketfd = 0,newfd = 0; + int clientfd[MAX_CLIENT_CONNECTIONS]; + int i, nextclientindex; + fd_set read_fds; + int fdmax; + int recvbytes; + int exit_received = 0; + + shaperLogInit(); + + while((c = getopt(argc,argv,"d"))>=0) + { + switch(c) + { + case 'd': + daemonize = 1; + break; + } + } + + if (daemonize == 1 && daemon(1,0) < 0) + { + SHAPER_LOGF_ERROR("Error %d (%s) starting the daemon", errno, strerror(errno)); + shaperLogExit(); + return 1; + } + + if ((socketfd = init_socket())<0) + { + shaperLogExit(); + return 1; + } + + for (i = 0; i < MAX_CLIENT_CONNECTIONS; ++i) + { + clientfd[i] = -1; + } + nextclientindex = 0; + + fputs(USER_COMMAND_PROMPT, stdout); + fflush(stdout); + + while (!exit_received) + { + FD_ZERO(&read_fds); + FD_SET(STDIN_FILENO, &read_fds); + FD_SET(socketfd, &read_fds); + fdmax = socketfd; + for (i = 0; i < MAX_CLIENT_CONNECTIONS; ++i) + { + if (clientfd[i]>0) + { + FD_SET(clientfd[i],&read_fds); + if (clientfd[i]>fdmax) + { + fdmax = clientfd[i]; + } + } + } + int n = select(fdmax+1,&read_fds,NULL,NULL,NULL); + if(n == -1) + { + SHAPER_LOGF_ERROR("select() error %d (%s)", errno, strerror(errno)); + break; + } + else + { + /* Handle any commands received via stdin. */ + if (FD_ISSET(STDIN_FILENO, &read_fds)) + { + recvbytes = read(STDIN_FILENO, command, sizeof(command) - 1); + if (recvbytes <= 0) + { + SHAPER_LOGF_ERROR("Error %d reading from stdin (%s)", errno, strerror(errno)); + } + else + { + command[recvbytes] = '\0'; + + /* Process the command data. */ + int ret = process_command(-1, command); + if (!ret) + { + /* Received a command to exit. */ + exit_received = 1; + } + else + { + /* Prompt the user again. */ + shaperLogDisplayAll(); + fputs(USER_COMMAND_PROMPT, stdout); + fflush(stdout); + } + } + } + + if (FD_ISSET(socketfd,&read_fds)) + { + newfd = accept(socketfd, (struct sockaddr*)NULL, NULL); + if (clientfd[nextclientindex] != -1) + { + /* Find the next available index. */ + for (i = (nextclientindex + 1) % MAX_CLIENT_CONNECTIONS; i != nextclientindex; i = (i + 1) % MAX_CLIENT_CONNECTIONS) + { + if (clientfd[nextclientindex] == -1) + { + /* Found an empty array slot. */ + break; + } + } + if (i == nextclientindex) + { + /* No more client slots available. Connection rejected. */ + SHAPER_LOG_WARNING("Out of client connection slots. Connection rejected."); + close(newfd); + newfd = -1; + } + } + + + if (newfd != -1) + { + clientfd[nextclientindex] = newfd; + nextclientindex = (nextclientindex + 1) % MAX_CLIENT_CONNECTIONS; /* Next slot used for the next try. */ + + /* Send a prompt to the user. */ + send(newfd, USER_COMMAND_PROMPT, strlen(USER_COMMAND_PROMPT), 0); + } + } + + for (i = 0; i < MAX_CLIENT_CONNECTIONS; ++i) + { + if (clientfd[i] != -1 && FD_ISSET(clientfd[i], &read_fds)) + { + recvbytes = recv(clientfd[i], command, sizeof(command) - 1, 0); + if (recvbytes < 0) + { + SHAPER_LOGF_ERROR("Error %d reading from socket %d (%s). Connection closed.", errno, clientfd[i], strerror(errno)); + close(clientfd[i]); + clientfd[i] = -1; + nextclientindex = i; /* We know this slot will be empty. */ + continue; + } + if (recvbytes == 0) + { + SHAPER_LOGF_INFO("Socket %d closed", clientfd[i]); + close(clientfd[i]); + clientfd[i] = -1; + nextclientindex = i; /* We know this slot will be empty. */ + continue; + } + + command[recvbytes] = '\0'; + while (recvbytes > 0 && isspace(command[recvbytes - 1])) + { + /* Remove trailing whitespace. */ + command[--recvbytes] = '\0'; + } + SHAPER_LOGF_INFO("The received command is \"%s\"",command); + int ret = process_command(clientfd[i], command); + if (!ret) + { + /* Received a command to exit. */ + exit_received = 1; + } + else + { + /* Send another prompt to the user. */ + send(clientfd[i], USER_COMMAND_PROMPT, strlen(USER_COMMAND_PROMPT), 0); + } + } + } + } + }//main while loop + + close(socketfd); + + /* Close any connected sockets. */ + for (i = 0; i < MAX_CLIENT_CONNECTIONS; ++i) { + if (clientfd[i] != -1) { + SHAPER_LOGF_INFO("Socket %d closed", clientfd[i]); + close(clientfd[i]); + clientfd[i] = -1; + } + } + + shaperLogExit(); + + return 0; +} diff --git a/daemons/shaper/src/shaper_helper_linux.h b/daemons/shaper/src/shaper_helper_linux.h new file mode 100644 index 00000000..14ee7dbf --- /dev/null +++ b/daemons/shaper/src/shaper_helper_linux.h @@ -0,0 +1,182 @@ +/************************************************************************************************************* +Copyright (c) 2016-2017, Harman International Industries, Incorporated +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*************************************************************************************************************/ + +#ifndef SHAPER_HELPER_LINUX_H +#define SHAPER_HELPER_LINUX_H + +#include <unistd.h> +#include <pthread.h> +#include <signal.h> +#include <time.h> +#include <semaphore.h> +#include <arpa/inet.h> +#include <errno.h> +#include <sys/mman.h> +#include <poll.h> +#include <fcntl.h> +#include <net/if.h> +#include <dlfcn.h> + +// Uncomment to use manual data alignment adjustments. Not needed for Linux +//#define DATA_ALIGNMENT_ADJUSTMENT 1 + +/// Number of nanoseconds in second +#define NANOSECONDS_PER_SECOND (1000000000ULL) +/// Number of nanoseconds in millisecond +#define NANOSECONDS_PER_MSEC (1000000L) +/// Number of nanoseconds in microsecond +#define NANOSECONDS_PER_USEC (1000L) +/// Number of microseconds in second +#define MICROSECONDS_PER_SECOND (1000000L) +/// Number of microseconds in millisecond +#define MICROSECONDS_PER_MSEC (1000L) + +#define SLEEP(sec) sleep(sec) +#define SLEEP_MSEC(mSec) usleep(mSec * 1000) +#define SLEEP_NSEC(nSec) usleep(nSec / 1000) +#define SLEEP_UNTIL_NSEC(nSec) xSleepUntilNSec(nSec) +inline static void xSleepUntilNSec(uint64_t nSec) +{ + struct timespec tmpTime; + tmpTime.tv_sec = nSec / NANOSECONDS_PER_SECOND; + tmpTime.tv_nsec = nSec % NANOSECONDS_PER_SECOND; + clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &tmpTime, NULL); +} + +#define RAND() random() +#define SRAND(seed) srandom(seed) + +#define PRAGMA_ALIGN_8 + +#define SIGNAL_CALLBACK_SETUP(__NAM, __CB) \ + struct sigaction __NAM; \ + __NAM.sa_handler = __CB + +#define SIGNAL_SIGNAL_SETUP(__SIG, __NAM, __CB, __ERR) \ + sigemptyset(&__NAM.sa_mask); \ + __NAM.sa_flags = 0; \ + __ERR = sigaction(__SIG, &__NAM, NULL) + + +// the following macros define thread related items +#define THREAD_TYPE(thread) \ +typedef struct \ +{ \ + pthread_t pthread; \ + int err; \ +} thread##_type; + +#define THREAD_DEFINITON(thread) \ +thread##_type thread##_ThreadData + +#define THREAD_CREATE(threadName, threadhandle, thread_attr_name, thread_function, thread_function_arg) \ + { \ + pthread_attr_t thread_attr; \ + do { \ + threadhandle##_ThreadData.err = pthread_attr_init(&thread_attr); \ + if (threadhandle##_ThreadData.err) break; \ + threadhandle##_ThreadData.err = pthread_attr_setstacksize(&thread_attr, threadName##_THREAD_STK_SIZE); \ + if (threadhandle##_ThreadData.err) break; \ + threadhandle##_ThreadData.err = pthread_create( \ + (pthread_t*)&threadhandle##_ThreadData.pthread, \ + &thread_attr, \ + thread_function, \ + (void*)thread_function_arg); \ + } while (0); \ + pthread_attr_destroy(&thread_attr); \ + } + +#define THREAD_SET_RT_PRIORITY(threadhandle, priority) \ + { \ + struct sched_param param; \ + param.__sched_priority = priority; \ + pthread_setschedparam(threadhandle##_ThreadData.pthread, SCHED_RR, ¶m); \ + } + +#define THREAD_PIN(threadhandle, affinity) \ + { \ + cpu_set_t cpuset; \ + int i1; \ + CPU_ZERO(&cpuset); \ + for (i1 = 0; i1 < 32; i1++) { \ + if (affinity & (1 << i1)) CPU_SET(i1, &cpuset); \ + } \ + pthread_setaffinity_np(threadhandle##_ThreadData.pthread, sizeof(cpu_set_t), &cpuset); \ + } + +#define THREAD_CHECK_ERROR(threadhandle, message, error) \ + do { \ + error=FALSE; \ + if (threadhandle##_ThreadData.err != 0) \ + { \ + SHAPER_LOGF_ERROR("Thread error: %s code: %d", message, threadhandle##_ThreadData.err); \ + error=TRUE; \ + break; \ + } \ + } while (0) + +#define THREAD_STARTTHREAD(err) +#define THREAD_KILL(threadhandle, signal) pthread_kill(threadhandle##_ThreadData.pthread, signal) +#define THREAD_JOINABLE(threadhandle) +#define THREAD_JOIN(threadhandle, signal) pthread_join(threadhandle##_ThreadData.pthread, (void**)signal) +#define THREAD_SLEEP(threadhandle, secs) sleep(secs) + +#define THREAD_SELF() pthread_self() +#define GET_PID() getpid() + +#define SEM_T(sem) sem_t sem; +#define SEM_ERR_T(err) int err; +#define SEM_INIT(sem, init, err) err = sem_init(&sem, 0, init); +#define SEM_WAIT(sem, err) err = sem_wait(&sem); +#define SEM_POST(sem, err) err = sem_post(&sem); +#define SEM_DESTROY(sem, err) err = sem_destroy(&sem); +#define SEM_IS_ERR_NONE(err) (0 == err) +#define SEM_IS_ERR_TIMEOUT(err) (ETIMEDOUT == err || -1 == err) +#define SEM_LOG_ERR(err) if (0 != err) SHAPER_LOGF_ERROR("Semaphore error code: %d", err); + +#define MUTEX_ATTR_TYPE_DEFAULT PTHREAD_MUTEX_DEFAULT +#define MUTEX_ATTR_TYPE_RECURSIVE PTHREAD_MUTEX_RECURSIVE +#define MUTEX_HANDLE(mutex_handle) pthread_mutex_t mutex_handle +#define MUTEX_ATTR_HANDLE(mutex_attr_name) pthread_mutexattr_t mutex_attr_name +#define MUTEX_ATTR_CREATE_ERR() static mutex_err +#define MUTEX_ATTR_INIT(mutex_attr_name) pthread_mutexattr_init(&mutex_attr_name) +#define MUTEX_ATTR_SET_TYPE(mutex_attr_name,type) pthread_mutexattr_settype(&mutex_attr_name, type) +#define MUTEX_ATTR_SET_NAME(mutex_attr_name, name) +#define MUTEX_CREATE_ERR() int mutex_err +#define MUTEX_CREATE(mutex_handle,mutex_attr_name) mutex_err=pthread_mutex_init(&mutex_handle, &mutex_attr_name) +#define MUTEX_LOCK(mutex_handle) mutex_err=pthread_mutex_lock(&mutex_handle) +#define MUTEX_UNLOCK(mutex_handle) mutex_err=pthread_mutex_unlock(&mutex_handle) +#define MUTEX_DESTROY(mutex_handle) mutex_err=pthread_mutex_destroy(&mutex_handle) +#define MUTEX_LOG_ERR(message) if (mutex_err) SHAPER_LOG_ERROR(message); +#define MUTEX_IS_ERR (mutex_err != 0) + +// Alternate simplified mutex mapping +#define MUTEX_HANDLE_ALT(mutex_handle) pthread_mutex_t mutex_handle +#define MUTEX_CREATE_ALT(mutex_handle) pthread_mutex_init(&mutex_handle, NULL) +#define MUTEX_LOCK_ALT(mutex_handle) pthread_mutex_lock(&mutex_handle) +#define MUTEX_UNLOCK_ALT(mutex_handle) pthread_mutex_unlock(&mutex_handle) +#define MUTEX_DESTROY_ALT(mutex_handle) pthread_mutex_destroy(&mutex_handle) + +#endif // SHAPER_HELPER_LINUX_H diff --git a/daemons/shaper/src/shaper_log.h b/daemons/shaper/src/shaper_log.h new file mode 100644 index 00000000..2b97726d --- /dev/null +++ b/daemons/shaper/src/shaper_log.h @@ -0,0 +1,261 @@ +/************************************************************************************************************* +Copyright (c) 2016-2017, Harman International Industries, Incorporated +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*************************************************************************************************************/ + +/* +* MODULE SUMMARY : A simple logging facility for use during +* development. +*/ + +#ifndef SHAPER_LOG_H +#define SHAPER_LOG_H 1 + +// ******** +// Merge Issue +// TODO: Restructure to remove #ifdef code. +// ******** + +#include <stdio.h> +#include <stdarg.h> +#include <string.h> + +// Uncomment SHAPER_LOG_ON to enable logging. +#define SHAPER_LOG_ON 1 + +// Uncomment SHAPER_LOG_ON_OVERRIDE to override all SHAPER_LOG_ON usage in the app to ensure all logs are off. +//#define SHAPER_LOG_ON_OVERRIDE 1 + +#ifdef SHAPER_LOG_ON_OVERRIDE +#ifdef SHAPER_LOG_ON +#undef SHAPER_LOG_ON +#endif +#endif + +#define SHAPER_LOG_LEVEL_NONE 0 +#define SHAPER_LOG_LEVEL_ERROR 1 +#define SHAPER_LOG_LEVEL_WARNING 2 +#define SHAPER_LOG_LEVEL_INFO 3 +#define SHAPER_LOG_LEVEL_STATUS 4 +#define SHAPER_LOG_LEVEL_DEBUG 5 +#define SHAPER_LOG_LEVEL_VERBOSE 6 + +// Special case development logging levels for use with SHAPER_LOGF_DEV and SHAPER_LOG_DEV +#define SHAPER_LOG_LEVEL_DEV_ON SHAPER_LOG_LEVEL_NONE +#define SHAPER_LOG_LEVEL_DEV_OFF SHAPER_LOG_LEVEL_VERBOSE + 1 + +// Default log level, can override in source files +#ifndef SHAPER_LOG_LEVEL +//#define SHAPER_LOG_LEVEL SHAPER_LOG_LEVEL_ERROR +//#define SHAPER_LOG_LEVEL SHAPER_LOG_LEVEL_INFO +#define SHAPER_LOG_LEVEL SHAPER_LOG_LEVEL_STATUS +//#define SHAPER_LOG_LEVEL SHAPER_LOG_LEVEL_DEBUG +//#define SHAPER_LOG_LEVEL SHAPER_LOG_LEVEL_VERBOSE +#endif + +#ifndef SHAPER_LOG_COMPANY +#define SHAPER_LOG_COMPANY "SHAPER" +#endif + +#ifndef SHAPER_LOG_COMPONENT +#define SHAPER_LOG_COMPONENT "SHAPER" +#endif + +// Log format options and sizes. Uncomment to include the formatted info. +#define LOG_MSG_LEN 1024 + +// The length of the full message +#define LOG_FULL_MSG_LEN 1024 + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +static const int SHAPER_LOG_TIME_INFO = FALSE; +#define LOG_TIME_LEN 9 +//#define LOG_TIME_LEN 1 + +static const int SHAPER_LOG_TIMESTAMP_INFO = TRUE; +#define LOG_TIMESTAMP_LEN 32 +//#define LOG_TIMESTAMP_LEN 1 + +static const int SHAPER_LOG_FILE_INFO = FALSE; +//#define LOG_FILE_LEN 256 +#define LOG_FILE_LEN 1 + +static const int SHAPER_LOG_PROC_INFO = FALSE; +//#define LOG_PROC_LEN 64 +#define LOG_PROC_LEN 1 + +static const int SHAPER_LOG_THREAD_INFO = FALSE; +//#define LOG_THREAD_LEN 64 +#define LOG_THREAD_LEN 1 + +#define LOG_RT_MSG_LEN 256 +//#define LOG_RT_MSG_LEN 1 + +#define SHAPER_LOG_OUTPUT_FD stderr +//#define SHAPER_LOG_OUTPUT_FD stdout + +#define SHAPER_LOG_STDOUT_CONSOLE_WIDTH 80 + +static const int SHAPER_LOG_EXTRA_NEWLINE = TRUE; + +// When SHAPER_LOG_FROM_THREAD the message output will be output from a separate thread/task +// Primary intended use is for debugging. +// It is expected that SHAPER_LOG_PULL_MODE will not be used at the same time as this option. +static const int SHAPER_LOG_FROM_THREAD = TRUE; + +// When SHAPER_LOG_PULL_MODE the messages will be queued and can be pulled using the +// shaperLogGetMsg() call. This could be from an logger interface module or host application. +// It is expected that SHAPER_LOG_FROM_THREAD will not be used at the same time as this option. +static const int SHAPER_LOG_PULL_MODE = FALSE; + +// When using the SHAPER_LOG_FROM_THREAD option. These defines control the behavior of the msg queue +#define LOG_QUEUE_MSG_LEN 256 +#define LOG_QUEUE_MSG_SIZE (LOG_QUEUE_MSG_LEN + 1) +#define LOG_QUEUE_MSG_CNT 82 +#define LOG_QUEUE_SLEEP_MSEC 100 + +// RT (RealTime logging) related defines +#define LOG_RT_QUEUE_CNT 128 +#define LOG_RT_BEGIN TRUE +#define LOG_RT_ITEM TRUE +#define LOG_RT_END TRUE +typedef enum { + LOG_RT_DATATYPE_NONE, + LOG_RT_DATATYPE_CONST_STR, + LOG_RT_DATATYPE_NOW_TS, + LOG_RT_DATATYPE_U16, + LOG_RT_DATATYPE_S16, + LOG_RT_DATATYPE_U32, + LOG_RT_DATATYPE_S32, + LOG_RT_DATATYPE_U64, + LOG_RT_DATATYPE_S64, + LOG_RT_DATATYPE_FLOAT +} log_rt_datatype_t; + + +#define LOG_VARX(x, y) x ## y +#define LOG_VAR(x, y) LOG_VARX(x, y) + +// Log a message once. Technically once every 4.2 billion attempts. Usage: LOG_ONCE SHAPER_LOG_INFO(...) +#define IF_LOG_ONCE() static uint32_t LOG_VAR(logOnce,__LINE__); if (!LOG_VAR(logOnce,__LINE__)++) + +// Log a message at an interval. Usage: LOG_INTERVAL(100) SHAPER_LOG_INFO(...) +#define IF_LOG_INTERVAL(x) static uint32_t LOG_VAR(logOnce,__LINE__); if (!(LOG_VAR(logOnce,__LINE__)++ % (x - 1))) + + +#define ETH_FORMAT "%02x:%02x:%02x:%02x:%02x:%02x" +#define ETH_OCTETS(a) (a)[0],(a)[1],(a)[2],(a)[3],(a)[4],(a)[5] + + +void shaperLogInit(void); + +void shaperLogDisplayAll(void); + +void shaperLogExit(void); + +void shaperLogFn( + int level, + const char *tag, + const char *company, + const char *component, + const char *path, + int line, + const char *fmt, + ...); + +void shaperLogRT(int level, int bBegin, int bItem, int bEnd, char *pFormat, log_rt_datatype_t dataType, void *pVar); + +void shaperLogBuffer( + int level, + const uint8_t *pData, + int dataLen, + int lineLen, + const char *company, + const char *component, + const char *path, + int line); + + +#define shaperLogFn2(level, tag, company, component, path, line, fmt, ...) \ + ({\ + if (level <= SHAPER_LOG_LEVEL) \ + shaperLogFn(0, tag, company, component, path, line, fmt, __VA_ARGS__); \ + }) + +#ifdef SHAPER_LOG_ON +#define SHAPER_LOGF_DEV(LEVEL, FMT, ...) shaperLogFn2(LEVEL, "DEV", SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__) +#define SHAPER_LOGF_ERROR(FMT, ...) shaperLogFn2(SHAPER_LOG_LEVEL_ERROR, "ERROR", SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__) +#define SHAPER_LOGF_WARNING(FMT, ...) shaperLogFn2(SHAPER_LOG_LEVEL_WARNING, "WARNING", SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__) +#define SHAPER_LOGF_INFO(FMT, ...) shaperLogFn2(SHAPER_LOG_LEVEL_INFO, "INFO", SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__) +#define SHAPER_LOGF_STATUS(FMT, ...) shaperLogFn2(SHAPER_LOG_LEVEL_STATUS, "STATUS", SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__) +#define SHAPER_LOGF_DEBUG(FMT, ...) shaperLogFn2(SHAPER_LOG_LEVEL_DEBUG, "DEBUG", SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__) +#define SHAPER_LOGF_VERBOSE(FMT, ...) shaperLogFn2(SHAPER_LOG_LEVEL_VERBOSE, "VERBOSE", SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__) +#define SHAPER_LOG_DEV(LEVEL, MSG) shaperLogFn2(LEVEL, "DEV", SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG) +#define SHAPER_LOG_ERROR(MSG) shaperLogFn2(SHAPER_LOG_LEVEL_ERROR, "ERROR", SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG) +#define SHAPER_LOG_WARNING(MSG) shaperLogFn2(SHAPER_LOG_LEVEL_WARNING, "WARNING", SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG) +#define SHAPER_LOG_INFO(MSG) shaperLogFn2(SHAPER_LOG_LEVEL_INFO, "INFO", SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG) +#define SHAPER_LOG_STATUS(MSG) shaperLogFn2(SHAPER_LOG_LEVEL_STATUS, "STATUS", SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG) +#define SHAPER_LOG_DEBUG(MSG) shaperLogFn2(SHAPER_LOG_LEVEL_DEBUG, "DEBUG", SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG) +#define SHAPER_LOG_VERBOSE(MSG) shaperLogFn2(SHAPER_LOG_LEVEL_VERBOSE, "VERBOSE", SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG) +#define SHAPER_LOGRT_ERROR(BEGIN, ITEM, END, FMT, TYPE, VAL) shaperLogRT(SHAPER_LOG_LEVEL_ERROR, BEGIN, ITEM, END, FMT, TYPE, VAL) +#define SHAPER_LOGRT_WARNING(BEGIN, ITEM, END, FMT, TYPE, VAL) shaperLogRT(SHAPER_LOG_LEVEL_WARNING, BEGIN, ITEM, END, FMT, TYPE, VAL) +#define SHAPER_LOGRT_INFO(BEGIN, ITEM, END, FMT, TYPE, VAL) shaperLogRT(SHAPER_LOG_LEVEL_INFO, BEGIN, ITEM, END, FMT, TYPE, VAL) +#define SHAPER_LOGRT_STATUS(BEGIN, ITEM, END, FMT, TYPE, VAL) shaperLogRT(SHAPER_LOG_LEVEL_STATUS, BEGIN, ITEM, END, FMT, TYPE, VAL) +#define SHAPER_LOGRT_DEBUG(BEGIN, ITEM, END, FMT, TYPE, VAL) shaperLogRT(SHAPER_LOG_LEVEL_DEBUG, BEGIN, ITEM, END, FMT, TYPE, VAL) +#define SHAPER_LOGRT_VERBOSE(BEGIN, ITEM, END, FMT, TYPE, VAL) shaperLogRT(SHAPER_LOG_LEVEL_VERBOSE, BEGIN, ITEM, END, FMT, TYPE, VAL) +#define SHAPER_LOG_BUFFER(LEVEL, DATA, DATALEN, LINELINE) shaperLogBuffer(LEVEL, DATA, DATALEN, LINELINE, SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__) +#else +#define SHAPER_LOGF_DEV(LEVEL, FMT, ...) +#define SHAPER_LOGF_ERROR(FMT, ...) +#define SHAPER_LOGF_WARNING(FMT, ...) +#define SHAPER_LOGF_INFO(FMT, ...) +#define SHAPER_LOGF_STATUS(FMT, ...) +#define SHAPER_LOGF_DEBUG(FMT, ...) +#define SHAPER_LOGF_VERBOSE(FMT, ...) +#define SHAPER_LOG_DEV(LEVEL, FMT, ...) +#define SHAPER_LOG_ERROR(MSG) +#define SHAPER_LOG_WARNING(MSG) +#define SHAPER_LOG_INFO(MSG) +#define SHAPER_LOG_STATUS(MSG) +#define SHAPER_LOG_DEBUG(MSG) +#define SHAPER_LOG_VERBOSE(MSG) +#define SHAPER_LOGRT_ERROR(BEGIN, ITEM, END, FMT, TYPE, VAL) +#define SHAPER_LOGRT_WARNING(BEGIN, ITEM, END, FMT, TYPE, VAL) +#define SHAPER_LOGRT_INFO(BEGIN, ITEM, END, FMT, TYPE, VAL) +#define SHAPER_LOGRT_STATUS(BEGIN, ITEM, END, FMT, TYPE, VAL) +#define SHAPER_LOGRT_DEBUG(BEGIN, ITEM, END, FMT, TYPE, VAL) +#define SHAPER_LOGRT_VERBOSE(BEGIN, ITEM, END, FMT, TYPE, VAL) +#define SHAPER_LOG_BUFFER(LEVEL, DATA, DATALEN, LINELINE) +#endif // SHAPER_LOG_ON + +// Get a queued log message. Intended to be used with the SHAPER_LOG_PULL_MODE option. +// Message will not be null terminated. +uint32_t shaperLogGetMsg(uint8_t *pBuf, uint32_t bufSize); + +#endif // SHAPER_LOG_H diff --git a/daemons/shaper/src/shaper_log_linux.c b/daemons/shaper/src/shaper_log_linux.c new file mode 100644 index 00000000..d68a79a2 --- /dev/null +++ b/daemons/shaper/src/shaper_log_linux.c @@ -0,0 +1,445 @@ +/************************************************************************************************************* +Copyright (c) 2016-2017, Harman International Industries, Incorporated +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*************************************************************************************************************/ + +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <inttypes.h> + +#include "platform.h" +#include "shaper_log_queue.h" +#include "shaper_helper_linux.h" + +#define SHAPER_LOG_COMPONENT "Log" +#include "shaper_log.h" + +typedef struct { + uint8_t msg[LOG_QUEUE_MSG_SIZE]; + int bRT; // TRUE = Details are in RT queue +} log_queue_item_t; + +typedef struct { + char *pFormat; + log_rt_datatype_t dataType; + union { + struct timespec nowTS; + uint16_t unsignedShortVar; + int16_t signedShortVar; + uint32_t unsignedLongVar; + int32_t signedLongVar; + uint64_t unsignedLongLongVar; + int64_t signedLongLongVar; + float floatVar; + } data; + int bEnd; +} log_rt_queue_item_t; + +static shaper_log_queue_t logQueue; +static shaper_log_queue_t logRTQueue; + +static char msg[LOG_MSG_LEN] = ""; +static char time_msg[LOG_TIME_LEN] = ""; +static char timestamp_msg[LOG_TIMESTAMP_LEN] = ""; +static char file_msg[LOG_FILE_LEN] = ""; +static char proc_msg[LOG_PROC_LEN] = ""; +static char thread_msg[LOG_THREAD_LEN] = ""; +static char full_msg[LOG_FULL_MSG_LEN] = ""; + +static char rt_msg[LOG_RT_MSG_LEN] = ""; + +static int loggingThreadRunning = FALSE; +extern void *loggingThreadFn(void *pv); +THREAD_TYPE(loggingThread); +THREAD_DEFINITON(loggingThread); + +#define THREAD_STACK_SIZE 65536 +#define loggingThread_THREAD_STK_SIZE THREAD_STACK_SIZE + +static MUTEX_HANDLE_ALT(gLogMutex); +#define LOG_LOCK() MUTEX_LOCK_ALT(gLogMutex) +#define LOG_UNLOCK() MUTEX_UNLOCK_ALT(gLogMutex) + +void shaperLogRTRender(log_queue_item_t *pLogItem) +{ + if (logRTQueue) { + pLogItem->msg[0] = 0x00; + int bMore = TRUE; + while (bMore) { + shaper_log_queue_elem_t elem = shaperLogQueueTailLock(logRTQueue); + if (elem) { + log_rt_queue_item_t *pLogRTItem = (log_rt_queue_item_t *)shaperLogQueueData(elem); + + switch (pLogRTItem->dataType) { + case LOG_RT_DATATYPE_CONST_STR: + strcat((char *)pLogItem->msg, pLogRTItem->pFormat); + break; + case LOG_RT_DATATYPE_NOW_TS: + sprintf(rt_msg, "[%lu:%09lu] ", pLogRTItem->data.nowTS.tv_sec, pLogRTItem->data.nowTS.tv_nsec); + strcat((char *)pLogItem->msg, rt_msg); + break; + case LOG_RT_DATATYPE_U16: + sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.unsignedShortVar); + strcat((char *)pLogItem->msg, rt_msg); + break; + case LOG_RT_DATATYPE_S16: + sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.signedShortVar); + strcat((char *)pLogItem->msg, rt_msg); + break; + case LOG_RT_DATATYPE_U32: + sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.unsignedLongVar); + strcat((char *)pLogItem->msg, rt_msg); + break; + case LOG_RT_DATATYPE_S32: + sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.signedLongVar); + strcat((char *)pLogItem->msg, rt_msg); + break; + case LOG_RT_DATATYPE_U64: + sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.unsignedLongLongVar); + strcat((char *)pLogItem->msg, rt_msg); + break; + case LOG_RT_DATATYPE_S64: + sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.signedLongLongVar); + strcat((char *)pLogItem->msg, rt_msg); + break; + case LOG_RT_DATATYPE_FLOAT: + sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.floatVar); + strcat((char *)pLogItem->msg, rt_msg); + break; + default: + break; + } + + if (pLogRTItem->bEnd) { + if (SHAPER_LOG_EXTRA_NEWLINE) + strcat((char *)pLogItem->msg, "\n"); + bMore = FALSE; + } + shaperLogQueueTailPull(logRTQueue); + } + } + } +} + +uint32_t shaperLogGetMsg(uint8_t *pBuf, uint32_t bufSize) +{ + uint32_t dataLen = 0; + if (logQueue) { + shaper_log_queue_elem_t elem = shaperLogQueueTailLock(logQueue); + if (elem) { + log_queue_item_t *pLogItem = (log_queue_item_t *)shaperLogQueueData(elem); + + if (pLogItem->bRT) + shaperLogRTRender(pLogItem); + + dataLen = strlen((const char *)pLogItem->msg); + if (dataLen <= bufSize) + memcpy(pBuf, (uint8_t *)pLogItem->msg, dataLen); + else + memcpy(pBuf, (uint8_t *)pLogItem->msg, bufSize); + shaperLogQueueTailPull(logQueue); + return dataLen; + } + } + return dataLen; +} + +void *loggingThreadFn(void *pv) +{ + (void) pv; + + while (loggingThreadRunning) { + SLEEP_MSEC(LOG_QUEUE_SLEEP_MSEC); + shaperLogDisplayAll(); + } + + return NULL; +} + +void shaperLogDisplayAll(void) +{ + int more = TRUE; + + while (more) { + more = FALSE; + shaper_log_queue_elem_t elem = shaperLogQueueTailLock(logQueue); + if (elem) { + log_queue_item_t *pLogItem = (log_queue_item_t *)shaperLogQueueData(elem); + + if (pLogItem->bRT) + shaperLogRTRender(pLogItem); + + fputs((const char *)pLogItem->msg, SHAPER_LOG_OUTPUT_FD); + shaperLogQueueTailPull(logQueue); + more = TRUE; + } + } +} + +void shaperLogInit(void) +{ + MUTEX_CREATE_ALT(gLogMutex); + + logQueue = shaperLogQueueNewQueue(sizeof(log_queue_item_t), LOG_QUEUE_MSG_CNT); + if (!logQueue) { + printf("Failed to initialize logging facility\n"); + } + + logRTQueue = shaperLogQueueNewQueue(sizeof(log_rt_queue_item_t), LOG_RT_QUEUE_CNT); + if (!logRTQueue) { + printf("Failed to initialize logging RT facility\n"); + } + + // Start the logging task + if (SHAPER_LOG_FROM_THREAD) { + int errResult; + loggingThreadRunning = TRUE; + THREAD_CREATE(loggingThread, loggingThread, NULL, loggingThreadFn, NULL); + THREAD_CHECK_ERROR(loggingThread, "Thread / task creation failed", errResult); + if (errResult) {} // Already reported + } +} + +void shaperLogExit() +{ + if (SHAPER_LOG_FROM_THREAD) { + loggingThreadRunning = FALSE; + THREAD_JOIN(loggingThread, NULL); + } +} + +void shaperLogFn( + int level, + const char *tag, + const char *company, + const char *component, + const char *path, + int line, + const char *fmt, + ...) +{ + if (level <= SHAPER_LOG_LEVEL) { + va_list args; + va_start(args, fmt); + + LOG_LOCK(); + + vsprintf(msg, fmt, args); + + if (SHAPER_LOG_FILE_INFO && path) { + char* file = strrchr(path, '/'); + if (!file) + file = strrchr(path, '\\'); + if (file) + file += 1; + else + file = (char*)path; + sprintf(file_msg, " %s:%d", file, line); + } + if (SHAPER_LOG_PROC_INFO) { + sprintf(proc_msg, " P:%5.5d", GET_PID()); + } + if (SHAPER_LOG_THREAD_INFO) { + sprintf(thread_msg, " T:%lu", THREAD_SELF()); + } + if (SHAPER_LOG_TIME_INFO) { + time_t tNow = time(NULL); + struct tm tmNow; + localtime_r(&tNow, &tmNow); + + sprintf(time_msg, "%2.2d:%2.2d:%2.2d", tmNow.tm_hour, tmNow.tm_min, tmNow.tm_sec); + } + if (SHAPER_LOG_TIMESTAMP_INFO) { + struct timespec nowTS; + clock_gettime(CLOCK_REALTIME, &nowTS); + + sprintf(timestamp_msg, "%lu:%09lu", nowTS.tv_sec, nowTS.tv_nsec); + } + + // using sprintf and puts allows using static buffers rather than heap. + if (SHAPER_LOG_EXTRA_NEWLINE) + /* int32_t full_msg_len = */ sprintf(full_msg, "[%s%s%s%s %s %s%s] %s: %s\n", time_msg, timestamp_msg, proc_msg, thread_msg, company, component, file_msg, tag, msg); + else + /* int32_t full_msg_len = */ sprintf(full_msg, "[%s%s%s%s %s %s%s] %s: %s", time_msg, timestamp_msg, proc_msg, thread_msg, company, component, file_msg, tag, msg); + + if (!SHAPER_LOG_FROM_THREAD && !SHAPER_LOG_PULL_MODE) { + fputs(full_msg, SHAPER_LOG_OUTPUT_FD); + } + else { + if (logQueue) { + shaper_log_queue_elem_t elem = shaperLogQueueHeadLock(logQueue); + if (elem) { + log_queue_item_t *pLogItem = (log_queue_item_t *)shaperLogQueueData(elem); + pLogItem->bRT = FALSE; + strncpy((char *)pLogItem->msg, full_msg, LOG_QUEUE_MSG_LEN); + shaperLogQueueHeadPush(logQueue); + } + } + } + + va_end(args); + + LOG_UNLOCK(); + } +} + +void shaperLogRT(int level, int bBegin, int bItem, int bEnd, char *pFormat, log_rt_datatype_t dataType, void *pVar) +{ + if (level <= SHAPER_LOG_LEVEL) { + if (logRTQueue) { + if (bBegin) { + LOG_LOCK(); + + shaper_log_queue_elem_t elem = shaperLogQueueHeadLock(logRTQueue); + if (elem) { + log_rt_queue_item_t *pLogRTItem = (log_rt_queue_item_t *)shaperLogQueueData(elem); + pLogRTItem->bEnd = FALSE; + pLogRTItem->pFormat = NULL; + pLogRTItem->dataType = LOG_RT_DATATYPE_NOW_TS; + clock_gettime(CLOCK_REALTIME, &pLogRTItem->data.nowTS); + shaperLogQueueHeadPush(logRTQueue); + } + } + + if (bItem) { + shaper_log_queue_elem_t elem = shaperLogQueueHeadLock(logRTQueue); + if (elem) { + log_rt_queue_item_t *pLogRTItem = (log_rt_queue_item_t *)shaperLogQueueData(elem); + if (bEnd) + pLogRTItem->bEnd = TRUE; + else + pLogRTItem->bEnd = FALSE; + pLogRTItem->pFormat = pFormat; + pLogRTItem->dataType = dataType; + + switch (pLogRTItem->dataType) { + case LOG_RT_DATATYPE_CONST_STR: + break; + case LOG_RT_DATATYPE_U16: + pLogRTItem->data.unsignedLongVar = *(uint16_t *)pVar; + break; + case LOG_RT_DATATYPE_S16: + pLogRTItem->data.signedLongVar = *(int16_t *)pVar; + break; + case LOG_RT_DATATYPE_U32: + pLogRTItem->data.unsignedLongVar = *(uint32_t *)pVar; + break; + case LOG_RT_DATATYPE_S32: + pLogRTItem->data.signedLongVar = *(int32_t *)pVar; + break; + case LOG_RT_DATATYPE_U64: + pLogRTItem->data.unsignedLongLongVar = *(uint64_t *)pVar; + break; + case LOG_RT_DATATYPE_S64: + pLogRTItem->data.signedLongLongVar = *(int64_t *)pVar; + break; + case LOG_RT_DATATYPE_FLOAT: + pLogRTItem->data.floatVar = *(float *)pVar; + break; + default: + break; + } + shaperLogQueueHeadPush(logRTQueue); + } + } + + if (!bItem && bEnd) { + shaper_log_queue_elem_t elem = shaperLogQueueHeadLock(logRTQueue); + if (elem) { + log_rt_queue_item_t *pLogRTItem = (log_rt_queue_item_t *)shaperLogQueueData(elem); + pLogRTItem->bEnd = TRUE; + pLogRTItem->pFormat = NULL; + pLogRTItem->dataType = LOG_RT_DATATYPE_NONE; + shaperLogQueueHeadPush(logRTQueue); + } + } + + if (bEnd) { + if (logQueue) { + shaper_log_queue_elem_t elem = shaperLogQueueHeadLock(logQueue); + if (elem) { + log_queue_item_t *pLogItem = (log_queue_item_t *)shaperLogQueueData(elem); + pLogItem->bRT = TRUE; + if (SHAPER_LOG_FROM_THREAD) { + shaperLogQueueHeadPush(logQueue); + } else { + shaperLogRTRender(pLogItem); + fputs((const char *)pLogItem->msg, SHAPER_LOG_OUTPUT_FD); + shaperLogQueueHeadUnlock(logQueue); + } + } + } + + LOG_UNLOCK(); + } + } + } +} + +void shaperLogBuffer( + int level, + const uint8_t *pData, + int dataLen, + int lineLen, + const char *company, + const char *component, + const char *path, + int line) +{ + char szDataLine[ 400 ]; + char *pszOut; + int i, j; + + if (level > SHAPER_LOG_LEVEL) { return; } + + for (i = 0; i < dataLen; i += lineLen) { + /* Create the hexadecimal output for the buffer. */ + pszOut = szDataLine; + *pszOut++ = '\t'; + for (j = i; j < i + lineLen; ++j) { + if (j < dataLen) { + sprintf(pszOut, "%02x ", pData[j]); + } else { + strcpy(pszOut, " "); + } + pszOut += 3; + } + + *pszOut++ = ' '; + *pszOut++ = ' '; + + /* Append the ASCII equivalent of each character. */ + for (j = i; j < dataLen && j < i + lineLen; ++j) { + if (pData[j] >= 0x20 && pData[j] < 0x7f) { + *pszOut++ = (char) pData[j]; + } else { + *pszOut++ = '.'; + } + } + + /* Display this line of text. */ + *pszOut = '\0'; + shaperLogFn(level, "BUFFER", company, component, path, line, "%s", szDataLine); + } +} diff --git a/daemons/shaper/src/shaper_log_queue.c b/daemons/shaper/src/shaper_log_queue.c new file mode 100644 index 00000000..52c6eb5e --- /dev/null +++ b/daemons/shaper/src/shaper_log_queue.c @@ -0,0 +1,200 @@ +/************************************************************************************************************* +Copyright (c) 2016-2017, Harman International Industries, Incorporated +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*************************************************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <inttypes.h> + +#include "shaper_log_queue.h" + +#define SHAPER_LOG_COMPONENT "Queue" +#include "shaper_log.h" + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +struct shaper_log_queue_elem { + int setFlg; + void *data; +}; + +struct shaper_log_queue { + // Size of each element + uint32_t elemSize; + + // Number of queue element slots + uint32_t queueSize; + + // Next element to be filled + uint32_t head; + + // Next element to be pulled + uint32_t tail; + + shaper_log_queue_elem_t elemArray; +}; + +shaper_log_queue_t shaperLogQueueNewQueue(uint32_t elemSize, uint32_t queueSize) +{ + if (elemSize < 1 || queueSize < 1) + return NULL; + + shaper_log_queue_t retQueue = calloc(1, sizeof(struct shaper_log_queue)); + if (retQueue) { + retQueue->elemArray = calloc(queueSize, sizeof(struct shaper_log_queue_elem)); + if (retQueue->elemArray) { + uint32_t i1; + for (i1 = 0; i1 < queueSize; i1++) { + retQueue->elemArray[i1].data = calloc(1, elemSize); + if (!retQueue->elemArray[i1].data) { + shaperLogQueueDeleteQueue(retQueue); + return NULL; + } + } + } + else { + shaperLogQueueDeleteQueue(retQueue); + return NULL; + } + + retQueue->elemSize = elemSize; + retQueue->queueSize = queueSize; + retQueue->head = 0; + retQueue->tail = 0; + } + + return retQueue; +} + +void shaperLogQueueDeleteQueue(shaper_log_queue_t queue) +{ + if (queue) { + uint32_t i1; + for (i1 = 0; i1 < queue->queueSize; i1++) { + free(queue->elemArray[i1].data); + queue->elemArray[i1].data = NULL; + } + free(queue->elemArray); + queue->elemArray = NULL; + free(queue); + } +} + +uint32_t shaperLogQueueGetQueueSize(shaper_log_queue_t queue) +{ + if (queue) { + return queue->queueSize; + } + return 0; +} + +uint32_t shaperLogQueueGetElemCount(shaper_log_queue_t queue) +{ + uint32_t cnt = 0; + if (queue) { + if (queue->head > queue->tail) { + cnt += queue->head - queue->tail - 1; + } + else if (queue->head < queue->tail) { + cnt += queue->head + ((queue->queueSize - 1) - queue->tail); + } + + if (queue->elemArray[queue->tail].setFlg) { + cnt++; + } + } + return cnt; +} + +uint32_t shaperLogQueueGetElemSize(shaper_log_queue_t queue) +{ + if (queue) { + return queue->elemSize; + } + return 0; +} + +void *shaperLogQueueData(shaper_log_queue_elem_t elem) +{ + if (elem) { + return elem->data; + } + return NULL; +} + +shaper_log_queue_elem_t shaperLogQueueHeadLock(shaper_log_queue_t queue) +{ + if (queue) { + if (!queue->elemArray[queue->head].setFlg) { + return &queue->elemArray[queue->head]; + } + } + return NULL; +} + +void shaperLogQueueHeadUnlock(shaper_log_queue_t queue) +{ + (void) queue; +} + +void shaperLogQueueHeadPush(shaper_log_queue_t queue) +{ + if (queue) { + queue->elemArray[queue->head++].setFlg = TRUE; + if (queue->head >= queue->queueSize) { + queue->head = 0; + } + } +} + +shaper_log_queue_elem_t shaperLogQueueTailLock(shaper_log_queue_t queue) +{ + if (queue) { + if (queue->elemArray[queue->tail].setFlg) { + return &queue->elemArray[queue->tail]; + } + } + return NULL; +} + +void shaperLogQueueTailUnlock(shaper_log_queue_t queue) +{ + (void) queue; +} + +void shaperLogQueueTailPull(shaper_log_queue_t queue) +{ + if (queue) { + queue->elemArray[queue->tail++].setFlg = FALSE; + if (queue->tail >= queue->queueSize) { + queue->tail = 0; + } + } +} diff --git a/daemons/shaper/src/shaper_log_queue.h b/daemons/shaper/src/shaper_log_queue.h new file mode 100644 index 00000000..5453fa8c --- /dev/null +++ b/daemons/shaper/src/shaper_log_queue.h @@ -0,0 +1,78 @@ +/************************************************************************************************************* +Copyright (c) 2016-2017, Harman International Industries, Incorporated +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*************************************************************************************************************/ + +/* +* MODULE SUMMARY : Interface for a basic dynamic array abstraction. +* +* - Fixed size queue. +* - Only head and tail access possible. +* - Head and Tail locking. +* - If there is a single task accessing head and a single task accessing tail no synchronization is needed. +* - If synchronization is needed the Pull and Push functions should be protected before calling. +*/ + +#ifndef SHAPER_LOG_QUEUE_H +#define SHAPER_LOG_QUEUE_H 1 + +typedef struct shaper_log_queue_elem * shaper_log_queue_elem_t; +typedef struct shaper_log_queue * shaper_log_queue_t; + +// Create an queue. Returns NULL on failure. +shaper_log_queue_t shaperLogQueueNewQueue(uint32_t elemSize, uint32_t queueSize); + +// Delete an array. +void shaperLogQueueDeleteQueue(shaper_log_queue_t queue); + +// Get number of queue slots +uint32_t shaperLogQueueGetQueueSize(shaper_log_queue_t queue); + +// Get number of element +uint32_t shaperLogQueueGetElemCount(shaper_log_queue_t queue); + +// Get element size +uint32_t shaperLogQueueGetElemSize(shaper_log_queue_t queue); + +// Get data of the element. Returns NULL on failure. +void *shaperLogQueueData(shaper_log_queue_elem_t elem); + +// Lock the head element. +shaper_log_queue_elem_t shaperLogQueueHeadLock(shaper_log_queue_t queue); + +// Unlock the head element. +void shaperLogQueueHeadUnlock(shaper_log_queue_t queue); + +// Push the head element making it available for tail access. +void shaperLogQueueHeadPush(shaper_log_queue_t queue); + +// Lock the tail element. +shaper_log_queue_elem_t shaperLogQueueTailLock(shaper_log_queue_t queue); + +// Unlock the tail element. +void shaperLogQueueTailUnlock(shaper_log_queue_t queue); + +// Pull (remove) the tail element +void shaperLogQueueTailPull(shaper_log_queue_t queue); + +#endif // SHAPER_LOG_QUEUE_H |