summaryrefslogtreecommitdiff
path: root/daemons
diff options
context:
space:
mode:
authorBrant Thomsen <brant.thomsen@harman.com>2017-06-09 12:49:03 -0600
committerBrant Thomsen <brant.thomsen@harman.com>2017-06-09 12:49:03 -0600
commit87521a71f8fa9323423dba456096618c01fc8f86 (patch)
tree3a5df17a5c61921e6915efc6cc4be4effde2ca11 /daemons
parent2b3fd1772c67d701e9fdb10fe95aea80887c45ea (diff)
downloadOpen-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/LICENSE25
-rw-r--r--daemons/shaper/Makefile37
-rw-r--r--daemons/shaper/src/platform.h74
-rw-r--r--daemons/shaper/src/shaper_daemon.c814
-rw-r--r--daemons/shaper/src/shaper_helper_linux.h182
-rw-r--r--daemons/shaper/src/shaper_log.h261
-rw-r--r--daemons/shaper/src/shaper_log_linux.c445
-rw-r--r--daemons/shaper/src/shaper_log_queue.c200
-rw-r--r--daemons/shaper/src/shaper_log_queue.h78
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, &param); \
+ }
+
+#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