MME2 changes - Propped commits from openmme/paging branch. Added scripts
for code gen
Change-Id: Ie55032217232214ac8544ca76ea34335205329e4
diff --git a/src/common/Makefile b/src/common/Makefile
new file mode 100644
index 0000000..1d5521b
--- /dev/null
+++ b/src/common/Makefile
@@ -0,0 +1,85 @@
+#
+# Copyright (c) 2003-2018, Great Software Laboratory Pvt. Ltd.
+# Copyright (c) 2017 Intel Corporation
+# Copyright (c) 2019, Infosys Ltd.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+include ../../Makefile.common
+
+ifeq ($(DEBUG),true)
+ CFLAGS += -g
+endif
+
+ifeq ($(DEBUG),false)
+ CFLAGS += -O3
+endif
+
+IF_LIBNAME = $(LIBDIR)/libinterface.so
+JSON_PARSER_LIBNAME = $(LIBDIR)/libjson.so
+LOG_LIBNAME = $(LIBDIR)/liblog.a
+TPOOL_LIBNAME = $(LIBDIR)/libthreadpool.a
+UTIL_LIBNAME = $(LIBDIR)/libsecutil.so
+
+IF_SRC = ./ipc_api.c
+LOG_SRC = ./log.c
+TPOOL_SRC = ./thread_pool.c ./tpool_queue.c
+JSON_PARSER_SRC = ./json_parser.c
+UTIL_SRC = ./snow_3g.c ./f8.c ./f9.c
+
+SRCDIR := .
+SRCEXT := c
+IF_OBJS := $(patsubst $(SRCDIR)/%,$(OBJDIR)/common/%,$(IF_SRC:.$(SRCEXT)=.o))
+LOG_OBJS := $(patsubst $(SRCDIR)/%,$(OBJDIR)/common/%,$(LOG_SRC:.$(SRCEXT)=.o))
+TPOOL_OBJS := $(patsubst $(SRCDIR)/%,$(OBJDIR)/common/%,$(TPOOL_SRC:.$(SRCEXT)=.o))
+JSON_PARSER_OBJS := $(patsubst $(SRCDIR)/%,$(OBJDIR)/common/%,$(JSON_PARSER_SRC:.$(SRCEXT)=.o))
+UTIL_OBJS := $(patsubst $(SRCDIR)/%,$(OBJDIR)/common/%,$(UTIL_SRC:.$(SRCEXT)=.o))
+
+OBJS := $(IF_OBJS) \
+ $(LOG_OBJS)\
+ $(TPOOL_OBJS) \
+ $(JSON_PARSER_OBJS) \
+ $(UTIL_OBJS)
+
+build_commonLibs: $(OBJS)
+ -@echo "Linking..."
+ -@mkdir -p $(LIBDIR)
+ $(CC) $(CFLAGS) $(IF_OBJS) -shared -o $(IF_LIBNAME)
+ $(CC) $(CFLAGS) $(JSON_PARSER_OBJS) -shared -o $(JSON_PARSER_LIBNAME)
+ $(CC) $(CFLAGS) $(UTIL_OBJS) -shared -o $(UTIL_LIBNAME)
+ ar rcs $(LOG_LIBNAME) $(LOG_OBJS)
+ ar rcs $(TPOOL_LIBNAME) $(TPOOL_OBJS)
+
+$(OBJS) : $(OBJDIR)/common/%.o : $(SRCDIR)/%.c
+ -@mkdir -p $(OBJDIR)/common
+ $(CC) $(CFLAGS) $(INC_DIRS) -fPIC -c -o $@ $<
+
+all: build_commonLibs
+
+install:all
+ -@mkdir -p $(TARGET_DIR)/lib
+ -@mkdir -p $(TARGET_DIR)/conf
+ -@cp $(IF_LIBNAME) $(TARGET_DIR)/lib
+ -@cp $(LOG_LIBNAME) $(TARGET_DIR)/lib
+ -@cp $(JSON_PARSER_LIBNAME) $(TARGET_DIR)/lib
+ -@cp $(UTIL_LIBNAME) $(TARGET_DIR)/lib
+ -@cp $(TPOOL_LIBNAME) $(TARGET_DIR)/lib
+
+clean:
+ rm -f $(OBJDIR)/common
+ rm -f $(IF_LIBNAME) \
+ $(JSON_PARSER_LIBNAME) \
+ $(UTIL_LIBNAME) \
+ $(LOG_LIBNAME) \
+ $(TPOOL_LIBNAME)
+
diff --git a/src/common/f8.c b/src/common/f8.c
new file mode 100644
index 0000000..dd43c42
--- /dev/null
+++ b/src/common/f8.c
@@ -0,0 +1,80 @@
+
+#include "f8.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+
+/* The code has been referred from
+ *
+ * 1.https://www.gsma.com/aboutus/wp-content/uploads/2014/12/uea2uia2d1v21.pdf
+ * 2.https://www.gsma.com/aboutus/wp-content/uploads/2014/12/snow3gspec.pdf
+ *
+ */
+
+
+
+/* f8.
+ * Input key: 128 bit Confidentiality Key.
+ * Input count:32-bit Count, Frame dependent input.
+ * Input bearer: 5-bit Bearer identity (in the LSB side).
+ * Input dir:1 bit, direction of transmission.
+ * Input data: length number of bits, input bit stream.
+ * Input length: 32 bit Length, i.e., the number of bits to be encrypted or
+ * decrypted.
+ * Output data: Output bit stream. Assumes data is suitably memory
+ * allocated.
+ * Encrypts/decrypts blocks of data between 1 and 2^32 bits in length as
+ * defined in Section 3.
+ */
+
+void f8( u8 *key, u32 count, u32 bearer, u32 dir, u8 *data, u32 length )
+{
+ u32 K[4],IV[4];
+ int n = ( length + 31 ) / 32;
+ int i=0;
+ u32 *KS;
+
+ /*Initialisation*/
+
+ /* Load the confidentiality key for SNOW 3G initialization as in section
+ 3.4.(https://www.gsma.com/aboutus/wp-content/uploads/2014/12/snow3gspec.pdf)
+ */
+
+ for (i=0; i<4; i++)
+ K[3-i] = (key[4*i] << 24) ^ (key[4*i+1] << 16) ^ (key[4*i+2] << 8) ^
+ (key[4*i+3]);
+
+ /* Prepare the initialization vector (IV) for SNOW 3G initialization as in
+ section 3.4.(https://www.gsma.com/aboutus/wp-content/uploads/2014/12/snow3gspec.pdf) */
+
+
+ IV[3] = count;
+ IV[2] = (bearer << 27) | ((dir & 0x1) << 26);
+ IV[1] = IV[3];
+ IV[0] = IV[2];
+
+ /* Run SNOW 3G algorithm to generate sequence of key stream bits KS*/
+
+ Initialize(K,IV);
+ KS = (u32 *)malloc(4*n);
+ GenerateKeystream(n,(u32*)KS);
+
+ /* Exclusive-OR the input data with keystream to generate the output bit
+ stream */
+
+ for (i=0; i<n; i++)
+ {
+ data[4*i+0] ^= (u8) (KS[i] >> 24) & 0xff;
+ data[4*i+1] ^= (u8) (KS[i] >> 16) & 0xff;
+ data[4*i+2] ^= (u8) (KS[i] >> 8) & 0xff;
+ data[4*i+3] ^= (u8) (KS[i] ) & 0xff;
+ }
+
+ free(KS);
+
+}
+/* End of f8.c */
+
+
diff --git a/src/common/f9.c b/src/common/f9.c
new file mode 100644
index 0000000..c001641
--- /dev/null
+++ b/src/common/f9.c
@@ -0,0 +1,210 @@
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+
+#include "f9.h"
+
+/* The code has been referred from
+ * 1.https://www.gsma.com/aboutus/wp-content/uploads/2014/12/uea2uia2d1v21.pdf
+ * 2.https://www.gsma.com/aboutus/wp-content/uploads/2014/12/snow3gspec.pdf
+ *
+ */
+
+
+/* MUL64x.
+ * Input V: a 64-bit input.
+ * Input c: a 64-bit input.
+ * Output : a 64-bit output.
+ * A 64-bit memory is allocated which is to be freed by the calling
+ * function.
+ * See section 4.3.2
+ * (https://www.gsma.com/aboutus/wp-content/uploads/2014/12/snow3gspec.pdf)
+ * for more details.
+ */
+
+
+u64 MUL64x(u64 V, u64 c)
+{
+ if ( V & 0x8000000000000000 )
+ return (V << 1) ^ c;
+ else
+ return V << 1;
+}
+
+/* MUL64xPOW.
+ * Input V: a 64-bit input.
+ * Input i: a positive integer.
+ * Input c: a 64-bit input.
+ * Output : a 64-bit output.
+ * A 64-bit memory is allocated which is to be freed by the calling
+ function.
+ * See section 4.3.3
+ * (https://www.gsma.com/aboutus/wp-content/uploads/2014/12/snow3gspec.pdf)
+ * for more details.
+ */
+
+u64 MUL64xPOW(u64 V, u8 i, u64 c)
+{
+ if ( i == 0)
+ return V;
+ else
+ return MUL64x( MUL64xPOW(V,i-1,c) , c);
+
+ return V;
+}
+
+/* MUL64.
+ * Input V: a 64-bit input.
+ * Input P: a 64-bit input.
+ * Input c: a 64-bit input.
+ * Output : a 64-bit output.
+ * A 64-bit memory is allocated which is to be freed by the calling
+ * function.
+ * See section 4.3.4
+ * (https://www.gsma.com/aboutus/wp-content/uploads/2014/12/snow3gspec.pdf)
+ * for more details.
+ */
+
+
+u64 MUL64(u64 V, u64 P, u64 c)
+{
+ u64 result = 0;
+ int i = 0;
+ for ( i=0; i<64; i++)
+ {
+ if( ( P>>i ) & 0x1 )
+ result ^= MUL64xPOW(V,i,c);
+ }
+
+ return result;
+}
+
+
+/* mask8bit.
+ * Input n: an integer in 1-7.
+ * Output : an 8 bit mask.
+ * Prepares an 8 bit mask with required number of 1 bits on the MSB side.
+ */
+
+u8 mask8bit(int n)
+{
+ return 0xFF ^ ((1<<(8-n)) - 1);
+}
+
+/* f9.
+ * Input key: 128 bit Integrity Key.
+ * Input count:32-bit Count, Frame dependent input.
+ * Input fresh: 32-bit Random number.
+ * Input dir:1 bit, direction of transmission (in the LSB).
+ * Input data: length number of bits, input bit stream.
+ * Input length: 64 bit Length, i.e., the number of bits to be MAC'd.
+ * Output : 32 bit block used as MAC
+ * Generates 32-bit MAC using UIA2 algorithm as defined in Section 4.
+ */
+
+u8* f9( u8* key, u32 count, u32 fresh, u32 dir, u8 *data, u64 length)
+{
+ u32 K[4],IV[4], z[5];
+ u32 i=0,D;
+ static u8 MAC_I[4] = {0,0,0,0}; /* static memory for the result */
+ u64 EVAL;
+ u64 V;
+ u64 P;
+ u64 Q;
+ u64 c;
+ u64 M_D_2;
+ int rem_bits = 0;
+
+ /* Load the Integrity Key for SNOW3G initialization as in section 4.4. */
+
+ for (i=0; i<4; i++)
+ K[3-i] = (key[4*i] << 24) ^ (key[4*i+1] << 16) ^ (key[4*i+2] << 8) ^
+ (key[4*i+3]);
+
+
+ /* Prepare the Initialization Vector (IV) for SNOW3G initialization as in
+ section 4.4 of
+ (https://www.gsma.com/aboutus/wp-content/uploads/2014/12/snow3gspec.pdf).
+ */
+
+ IV[3] = count;
+ IV[2] = fresh;
+ IV[1] = count ^ ( dir << 31 ) ;
+ IV[0] = fresh ^ (dir << 15);
+ z[0] = z[1] = z[2] = z[3] = z[4] = 0;
+
+ /* Run SNOW 3G to produce 5 keystream words z_1, z_2, z_3, z_4 and z_5. */
+
+ Initialize(K,IV);
+ GenerateKeystream(5,z);
+
+ P = (u64)z[0] << 32 | (u64)z[1];
+ Q = (u64)z[2] << 32 | (u64)z[3];
+
+ /* Calculation */
+
+ if ((length % 64) == 0)
+ D = (length>>6) + 1;
+ else
+ D = (length>>6) + 2;
+
+ EVAL = 0;
+ c = 0x1b;
+
+ /* for 0 <= i <= D-3 */
+
+ for (i=0;i<D-2;i++)
+ {
+ V = EVAL ^ ( (u64)data[8*i ]<<56 | (u64)data[8*i+1]<<48 |
+ (u64)data[8*i+2]<<40 | (u64)data[8*i+3]<<32 |
+ (u64)data[8*i+4]<<24 | (u64)data[8*i+5]<<16 |
+ (u64)data[8*i+6]<< 8 | (u64)data[8*i+7] );
+
+ EVAL = MUL64(V,P,c);
+ }
+
+ /* for D-2 */
+
+ rem_bits = length % 64;
+ if (rem_bits == 0)
+ rem_bits = 64;
+
+ M_D_2 = 0;
+ i = 0;
+
+ while (rem_bits > 7)
+ {
+ M_D_2 |= (u64)data[8*(D-2)+i] << (8*(7-i));
+ rem_bits -= 8;
+ i++;
+ }
+
+ if (rem_bits > 0)
+ M_D_2 |= (u64)(data[8*(D-2)+i] & mask8bit(rem_bits)) << (8*(7-i));
+
+ V = EVAL ^ M_D_2;
+ EVAL = MUL64(V,P,c);
+
+ /* for D-1 */
+
+ EVAL ^= length;
+
+ /* Multiply by Q */
+
+ EVAL = MUL64(EVAL,Q,c);
+
+ for (i=0; i<4; i++) {
+
+ /* GSLab-Intel modification to the specs reference code
+ * https://www.gsma.com/aboutus/wp-content/uploads/2014/12/uea2uia2d1v21.pdf
+ * which forgot to XOR z[5]
+ */
+
+ MAC_I[i] = ((EVAL >> (8 * (7-i))) ^ (z[4] >> (8 * (3-i)))) & 0xff;
+
+ }
+ return MAC_I;
+
+}
+/* End of f9.c */
+/*------------------------------------------------------------------------*/
diff --git a/src/common/ipc_api.c b/src/common/ipc_api.c
new file mode 100644
index 0000000..f682c18
--- /dev/null
+++ b/src/common/ipc_api.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2003-2018, Great Software Laboratory Pvt. Ltd.
+ * Copyright (c) 2017 Intel Corporation
+ * Copyright (c) 2019, Infosys Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <linux/tipc.h>
+#include <stdint.h>
+#include "log.h"
+#include "ipc_api.h"
+#include "err_codes.h"
+
+#include <sys/socket.h>
+#include <string.h>
+
+#define TIPC_SERVICE_ADDR 2
+
+int
+create_ipc_channel(char *name)
+{
+ if (mkfifo (name, IPC_MODE) == -1) {
+ log_msg(LOG_ERROR, "Error in create_ipc_channel %s\n", name);
+ perror("Error:");
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+open_ipc_channel(char *name, enum ipc_access_mode access_mode)
+{
+ int mode = O_RDONLY;
+ int fd;
+
+ if (access_mode == IPC_WRITE)
+ mode = O_WRONLY;
+
+ if ((fd = open(name, mode)) == -1) {
+ log_msg(LOG_ERROR, "Error in create_ipc_channel %s\n",name);
+ perror("Error:");
+ return -E_FAIL;
+ }
+
+ return fd;
+}
+
+int
+create_open_ipc_channel(char *name, enum ipc_access_mode access_mode)
+{
+ if (create_ipc_channel(name) != 0)
+ return -1;
+
+ return open_ipc_channel(name, access_mode);
+}
+
+int
+read_ipc_channel(ipc_handle fd, char *buffer, size_t size)
+{
+ int len = read(fd, buffer, size);
+ switch (len) {
+ case -1:
+ // case -1 means pipe is empty and errono
+ // set EAGAIN
+ if (errno == EAGAIN) {
+ log_msg(LOG_ERROR, "pipe empty \n");
+ usleep(5);
+ return -1;
+ }
+ else { perror("read");
+ exit(4);
+ }
+
+ // case 0 means all bytes are read and EOF(end of conv.)
+ case 0:
+ log_msg(LOG_ERROR, "End of conversation\n");
+
+ // read link
+ //close(p[0]);
+
+ exit(0);
+ default:
+ // text read
+ // by default return no. of bytes
+ // which read call read at that time
+ return len;
+ }
+}
+
+int
+write_ipc_channel(ipc_handle fd, char *buffer, size_t size)
+{
+ return write(fd, buffer, size);
+}
+
+int
+close_ipc_channel(ipc_handle fd)
+{
+ if (close(fd) == -1)
+ return -1;
+
+ return 0;
+}
+
+int
+create_tipc_socket()
+{
+ int sockFd = socket(AF_TIPC, SOCK_RDM, 0);
+
+ if (sockFd <= 0)
+ {
+ log_msg(LOG_INFO, "Failed to create tipc socket error: %s", strerror(errno));
+ }
+
+ return sockFd;
+}
+
+int
+bind_tipc_socket(int sockFd, uint32_t instanceNum)
+{
+ struct sockaddr_tipc server;
+
+ server.family = AF_TIPC;
+ server.addrtype = TIPC_SERVICE_ADDR;
+ server.scope = TIPC_CLUSTER_SCOPE;
+ server.addr.name.name.type = tipcServiceAddressType_c;
+ server.addr.name.name.instance = instanceNum;
+
+ int rc = 1;
+ if (0 != bind(sockFd, (void *)&server, sizeof(server)))
+ {
+ log_msg(LOG_ERROR, "Server: failed to bind port name %s\n", strerror(errno));
+ rc = -1;
+ }
+ else
+ {
+ log_msg(LOG_INFO, "Server: Success %s %d\n", strerror(errno), rc);
+ }
+ return rc;
+}
+
+int
+send_tipc_message(int sd, uint32_t destAddr, void * buf, int len)
+{
+ struct sockaddr_tipc server;
+ server.family = AF_TIPC;
+ server.addrtype = TIPC_SERVICE_ADDR;
+ server.scope = TIPC_CLUSTER_SCOPE;
+ server.addr.name.domain = 0;
+ server.addr.name.name.type = tipcServiceAddressType_c;
+ server.addr.name.name.instance = destAddr;
+
+ int rc = 0;
+ if (0 > sendto(sd, buf, len, 0, (void*)&server, sizeof(server)))
+ {
+ log_msg(LOG_ERROR, "FAILED TO SENT TIPC MESSAGE %s\n", strerror(errno));
+ } else {
+ rc = 1;
+ log_msg(LOG_INFO, "TIPC Message sent successfully to %d\n", destAddr);
+ }
+
+ return rc;
+}
+
+int
+read_tipc_msg(int sockFd, void * buf, int len)
+{
+ int bytesRead = 0;
+
+ if ((bytesRead = recv(sockFd, buf, len, 0)) <= 0)
+ {
+ log_msg(LOG_ERROR, "FAILED TO READ TIPC MESSAGE %s\n", strerror(errno));
+ }
+ return bytesRead;
+}
+
+void
+close_tipc_socket(int sockFd)
+{
+ close(sockFd);
+}
+
+
+
diff --git a/src/common/json_parser.c b/src/common/json_parser.c
new file mode 100644
index 0000000..a968ba6
--- /dev/null
+++ b/src/common/json_parser.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2003-2018, Great Software Laboratory Pvt. Ltd.
+ * Copyright (c) 2017 Intel Corporation
+ * Copyright (c) 2019, Infosys Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "log.h"
+
+FILE *json_fp;
+
+static char *
+seek_to_tag(char *name)
+{
+ char *tmp = name;
+ char tag[64] = {0};
+ char last_iteration = 0;
+
+ rewind(json_fp);
+
+ tmp = strchr(name, '.');
+ strncpy(tag, name, tmp-name);
+ ++tmp;
+
+ while(1) {
+ char tag_not_found = 1;
+ char *line =(char *) calloc(1, 128);
+ char *entry;
+ char *tmp2;
+
+ while(tag_not_found) {
+ if (NULL == fgets(line, 128, json_fp)) return NULL;
+ if(NULL != (entry = strstr(line, tag))) {
+ tag_not_found = 0; /*found*/
+ if(last_iteration) return line;
+ break;
+ }
+ if(feof(json_fp)) return NULL;
+ }
+#if 0
+ if(NULL == strchr(tmp, '.')) {
+ /*This is the last tag*/
+ return line;
+ }
+#endif
+ tmp2 = strchr(tmp, '.');
+ if(NULL == tmp2) {
+ last_iteration = 1;
+ tmp2 = tmp+strlen(tmp);
+ }
+ memset(tag, 0, 64);
+ strncpy(tag, tmp, tmp2-tmp);
+ tmp = tmp2+1;
+ tag_not_found = 1;/*seach for next tag*/
+ }
+
+}
+
+char *
+get_string_scalar(char *path)
+{
+ char *entry = seek_to_tag(path);
+ char *value = calloc(1, 128);
+
+ if(NULL == entry) {
+ log_msg(LOG_ERROR, "%s: entry not found\n", path);
+ free(value);
+ return NULL;
+ }
+
+ if (NULL == value)
+ {
+ log_msg(LOG_ERROR,"calloc function fail");
+ return NULL;
+ }
+ char *tmp = strchr(entry, ':');
+ sscanf(tmp, ": \"%[^\"]", value);
+ log_msg(LOG_INFO, "%s = %s\n", path, value);
+ return value;
+}
+
+int
+get_int_scalar(char *path)
+{
+ char *entry = seek_to_tag(path);
+ unsigned int i = 0;
+
+ if(NULL == entry) {
+ log_msg(LOG_ERROR, "%s: entry not found\n", path);
+ return -1;
+ }
+ char *tmp = strchr(entry, ':');
+
+ i = atoi(tmp+1);
+
+ free(entry);
+ log_msg(LOG_INFO, "%s = %d\n", path, i);
+ return i;
+}
+
+
+int
+get_ip_scalar(char *path)
+{
+ char *val = get_string_scalar(path);
+ unsigned int addr = 0;
+
+ if(NULL == val) addr = -1;
+ else addr = inet_addr(val);
+
+ free(val);
+ return ntohl(addr);
+}
+
+int
+load_json(char *filename)
+{
+ json_fp = fopen(filename, "r");
+
+ if(NULL == json_fp) {
+ log_msg(LOG_ERROR, "Error opening json file\n");
+ perror("Error:");
+ return -1;
+ }
+
+ return 0;
+}
+
+/** TEST CODE
+void
+main()
+{
+
+ load_json("test.json");
+ get_string_scalar("root.scalar1");
+ get_string_scalar("root.scalar2");
+ get_string_scalar("root.scalarx");
+ get_string_scalar("root.scalar3");
+ get_string_scalar("root.scalar4");
+ get_string_scalar("root.nested.scalar5");
+}
+**/
diff --git a/src/common/log.c b/src/common/log.c
new file mode 100644
index 0000000..cad7e36
--- /dev/null
+++ b/src/common/log.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2003-2018, Great Software Laboratory Pvt. Ltd.
+ * Copyright (c) 2017 Intel Corporation
+ * Copyright (c) 2019, Infosys Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <time.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "log.h"
+#include <sys/syscall.h>
+
+bool g_nolog = false;
+enum log_levels g_log_level = LOG_INFO;
+
+int pid = 0;
+char processName[255] = {0};
+
+static const char *log_level_name[] = { "INFO", "DEBUG", "WARN", "ERROR" };
+
+void log_message(int l, const char *file, int line, const char *fmt, ...)
+{
+ va_list arg;
+ if (g_nolog) return;
+ if(g_log_level > l) return;
+
+ FILE *fp = fopen("/tmp/mmelogs.txt", "a+");
+ if (fp == NULL)
+ {
+ printf("Could not open log file");
+ exit(0);
+ }
+
+ fprintf(fp,"%s(%d:%ld):%s-%s:%d:", processName, pid, syscall(SYS_gettid), log_level_name[l], file, line);
+ va_start(arg, fmt);
+// vfprintf(stderr, fmt, arg);
+ vfprintf(fp, fmt, arg);
+ va_end(arg);
+ fclose(fp);
+// fprintf(stderr, "\n");
+}
+
diff --git a/src/common/snow_3g.c b/src/common/snow_3g.c
new file mode 100644
index 0000000..045a10e
--- /dev/null
+++ b/src/common/snow_3g.c
@@ -0,0 +1,406 @@
+/*------------------------------------------------------------------
+* SNOW_3G.c
+*-------------------------------------------------------------------*/
+
+/*
+ * The code has been referred from
+ * 1. https://www.gsma.com/aboutus/wp-content/uploads/2014/12/snow3gspec.pdf
+ * 2. https://www.gsma.com/aboutus/wp-content/uploads/2014/12/uea2uia2d1v21.pdf
+*/
+
+
+#include "snow_3g.h"
+
+/* LFSR */
+
+u32 LFSR_S0 = 0x00;
+u32 LFSR_S1 = 0x00;
+u32 LFSR_S2 = 0x00;
+u32 LFSR_S3 = 0x00;
+u32 LFSR_S4 = 0x00;
+u32 LFSR_S5 = 0x00;
+u32 LFSR_S6 = 0x00;
+u32 LFSR_S7 = 0x00;
+u32 LFSR_S8 = 0x00;
+u32 LFSR_S9 = 0x00;
+u32 LFSR_S10 = 0x00;
+u32 LFSR_S11 = 0x00;
+u32 LFSR_S12 = 0x00;
+u32 LFSR_S13 = 0x00;
+u32 LFSR_S14 = 0x00;
+u32 LFSR_S15 = 0x00;
+
+/* FSM */
+
+u32 FSM_R1 = 0x00;
+u32 FSM_R2 = 0x00;
+u32 FSM_R3 = 0x00;
+
+
+/* Rijndael S-box SR */
+
+u8 SR[256] = {
+0x63,0x7C,0x77,0x7B,0xF2,0x6B,0x6F,0xC5,0x30,0x01,0x67,0x2B,0xFE,0xD7,0xAB,0x76,
+0xCA,0x82,0xC9,0x7D,0xFA,0x59,0x47,0xF0,0xAD,0xD4,0xA2,0xAF,0x9C,0xA4,0x72,0xC0,
+0xB7,0xFD,0x93,0x26,0x36,0x3F,0xF7,0xCC,0x34,0xA5,0xE5,0xF1,0x71,0xD8,0x31,0x15,
+0x04,0xC7,0x23,0xC3,0x18,0x96,0x05,0x9A,0x07,0x12,0x80,0xE2,0xEB,0x27,0xB2,0x75,
+0x09,0x83,0x2C,0x1A,0x1B,0x6E,0x5A,0xA0,0x52,0x3B,0xD6,0xB3,0x29,0xE3,0x2F,0x84,
+0x53,0xD1,0x00,0xED,0x20,0xFC,0xB1,0x5B,0x6A,0xCB,0xBE,0x39,0x4A,0x4C,0x58,0xCF,
+0xD0,0xEF,0xAA,0xFB,0x43,0x4D,0x33,0x85,0x45,0xF9,0x02,0x7F,0x50,0x3C,0x9F,0xA8,
+0x51,0xA3,0x40,0x8F,0x92,0x9D,0x38,0xF5,0xBC,0xB6,0xDA,0x21,0x10,0xFF,0xF3,0xD2,
+0xCD,0x0C,0x13,0xEC,0x5F,0x97,0x44,0x17,0xC4,0xA7,0x7E,0x3D,0x64,0x5D,0x19,0x73,
+0x60,0x81,0x4F,0xDC,0x22,0x2A,0x90,0x88,0x46,0xEE,0xB8,0x14,0xDE,0x5E,0x0B,0xDB,
+0xE0,0x32,0x3A,0x0A,0x49,0x06,0x24,0x5C,0xC2,0xD3,0xAC,0x62,0x91,0x95,0xE4,0x79,
+0xE7,0xC8,0x37,0x6D,0x8D,0xD5,0x4E,0xA9,0x6C,0x56,0xF4,0xEA,0x65,0x7A,0xAE,0x08,
+0xBA,0x78,0x25,0x2E,0x1C,0xA6,0xB4,0xC6,0xE8,0xDD,0x74,0x1F,0x4B,0xBD,0x8B,0x8A,
+0x70,0x3E,0xB5,0x66,0x48,0x03,0xF6,0x0E,0x61,0x35,0x57,0xB9,0x86,0xC1,0x1D,0x9E,
+0xE1,0xF8,0x98,0x11,0x69,0xD9,0x8E,0x94,0x9B,0x1E,0x87,0xE9,0xCE,0x55,0x28,0xDF,
+0x8C,0xA1,0x89,0x0D,0xBF,0xE6,0x42,0x68,0x41,0x99,0x2D,0x0F,0xB0,0x54,0xBB,0x16
+};
+
+/* S-box SQ */
+
+u8 SQ[256] = {
+0x25,0x24,0x73,0x67,0xD7,0xAE,0x5C,0x30,0xA4,0xEE,0x6E,0xCB,0x7D,0xB5,0x82,0xDB,
+0xE4,0x8E,0x48,0x49,0x4F,0x5D,0x6A,0x78,0x70,0x88,0xE8,0x5F,0x5E,0x84,0x65,0xE2,
+0xD8,0xE9,0xCC,0xED,0x40,0x2F,0x11,0x28,0x57,0xD2,0xAC,0xE3,0x4A,0x15,0x1B,0xB9,
+0xB2,0x80,0x85,0xA6,0x2E,0x02,0x47,0x29,0x07,0x4B,0x0E,0xC1,0x51,0xAA,0x89,0xD4,
+0xCA,0x01,0x46,0xB3,0xEF,0xDD,0x44,0x7B,0xC2,0x7F,0xBE,0xC3,0x9F,0x20,0x4C,0x64,
+0x83,0xA2,0x68,0x42,0x13,0xB4,0x41,0xCD,0xBA,0xC6,0xBB,0x6D,0x4D,0x71,0x21,0xF4,
+0x8D,0xB0,0xE5,0x93,0xFE,0x8F,0xE6,0xCF,0x43,0x45,0x31,0x22,0x37,0x36,0x96,0xFA,
+0xBC,0x0F,0x08,0x52,0x1D,0x55,0x1A,0xC5,0x4E,0x23,0x69,0x7A,0x92,0xFF,0x5B,0x5A,
+0xEB,0x9A,0x1C,0xA9,0xD1,0x7E,0x0D,0xFC,0x50,0x8A,0xB6,0x62,0xF5,0x0A,0xF8,0xDC,
+0x03,0x3C,0x0C,0x39,0xF1,0xB8,0xF3,0x3D,0xF2,0xD5,0x97,0x66,0x81,0x32,0xA0,0x00,
+0x06,0xCE,0xF6,0xEA,0xB7,0x17,0xF7,0x8C,0x79,0xD6,0xA7,0xBF,0x8B,0x3F,0x1F,0x53,
+0x63,0x75,0x35,0x2C,0x60,0xFD,0x27,0xD3,0x94,0xA5,0x7C,0xA1,0x05,0x58,0x2D,0xBD,
+0xD9,0xC7,0xAF,0x6B,0x54,0x0B,0xE0,0x38,0x04,0xC8,0x9D,0xE7,0x14,0xB1,0x87,0x9C,
+0xDF,0x6F,0xF9,0xDA,0x2A,0xC4,0x59,0x16,0x74,0x91,0xAB,0x26,0x61,0x76,0x34,0x2B,
+0xAD,0x99,0xFB,0x72,0xEC,0x33,0x12,0xDE,0x98,0x3B,0xC0,0x9B,0x3E,0x18,0x10,0x3A,
+0x56,0xE1,0x77,0xC9,0x1E,0x9E,0x95,0xA3,0x90,0x19,0xA8,0x6C,0x09,0xD0,0xF0,0x86
+};
+
+
+/* MULx.
+ * Input V: an 8-bit input.
+ * Input c: an 8-bit input.
+ * Output : an 8-bit output.
+ * See section 3.1.1 of
+ * https://www.gsma.com/aboutus/wp-content/uploads/2014/12/snow3gspec.pdf
+ * for details.
+ */
+
+
+u8 MULx(u8 V, u8 c)
+{
+ if ( V & 0x80 )
+ return ( (V << 1) ^ c);
+ else
+ return ( V << 1);
+}
+
+/* MULxPOW.
+ * Input V: an 8-bit input.
+ * Input i: a positive integer.
+ * Input c: an 8-bit input.
+ * Output : an 8-bit output.
+ * See section 3.1.2
+ * https://www.gsma.com/aboutus/wp-content/uploads/2014/12/snow3gspec.pdf
+ * for details.
+ */
+
+
+u8 MULxPOW(u8 V, u8 i, u8 c)
+{
+ /*GSLab-Intel modification to avoid recurssion*/
+ while(i > 0) {
+ V = ( V & 0x80 ) ? ( (V << 1) ^ c): ( V << 1);
+ --i;
+ }
+ return V;
+
+}
+/* The function MUL alpha.
+ * Input c: 8-bit input.
+ * Output : 32-bit output.
+ * See section 3.4.2
+ * https://www.gsma.com/aboutus/wp-content/uploads/2014/12/snow3gspec.pdf
+ * for details.
+ */
+
+u32 MULalpha(u8 c)
+{
+ return ( ( ((u32)MULxPOW(c, 23, 0xa9)) << 24 ) |
+ ( ((u32)MULxPOW(c, 245, 0xa9)) << 16 ) |
+ ( ((u32)MULxPOW(c, 48, 0xa9)) << 8 ) |
+ ((u32)MULxPOW(c, 239, 0xa9)) ) ;
+}
+
+/* The function DIV alpha.
+ * Input c: 8-bit input.
+ * Output : 32-bit output.
+ * See section 3.4.3
+ * https://www.gsma.com/aboutus/wp-content/uploads/2014/12/snow3gspec.pdf
+ * for details.
+ */
+
+u32 DIValpha(u8 c)
+{
+ return ( ( ((u32)MULxPOW(c, 16, 0xa9)) << 24 ) |
+ ( ((u32)MULxPOW(c, 39, 0xa9)) << 16 ) |
+ ( ((u32)MULxPOW(c, 6, 0xa9)) << 8 ) |
+ ( ((u32)MULxPOW(c, 64, 0xa9)) ) ) ;
+}
+
+/* The 32x32-bit S-Box S1
+ * Input: a 32-bit input.
+ * Output: a 32-bit output of S1 box.
+ * See section 3.3.1
+ * https://www.gsma.com/aboutus/wp-content/uploads/2014/12/snow3gspec.pdf
+ * for details.
+ */
+
+u32 S1(u32 w)
+{
+ u8 r0=0, r1=0, r2=0, r3=0;
+ u8 srw0 = SR[ (u8)((w >> 24) & 0xff) ];
+ u8 srw1 = SR[ (u8)((w >> 16) & 0xff) ];
+ u8 srw2 = SR[ (u8)((w >> 8) & 0xff) ];
+ u8 srw3 = SR[ (u8)((w) & 0xff) ];
+
+ r0 = ( ( MULx( srw0 , 0x1b) ) ^
+ ( srw1 ) ^
+ ( srw2 ) ^
+ ( (MULx( srw3, 0x1b)) ^ srw3 )
+ );
+
+ r1 = ( ( ( MULx( srw0 , 0x1b) ) ^ srw0 ) ^
+ ( MULx(srw1, 0x1b) ) ^
+ ( srw2 ) ^
+ ( srw3 )
+ );
+
+ r2 = ( ( srw0 ) ^
+ ( ( MULx( srw1 , 0x1b) ) ^ srw1 ) ^
+ ( MULx(srw2, 0x1b) ) ^
+ ( srw3 )
+ );
+
+ r3 = ( ( srw0 ) ^
+ ( srw1 ) ^
+ ( ( MULx( srw2 , 0x1b) ) ^ srw2 ) ^
+ ( MULx( srw3, 0x1b) )
+ );
+
+ return ( ( ((u32)r0) << 24 ) | ( ((u32)r1) << 16 ) | ( ((u32)r2) << 8 ) |
+ ( ((u32)r3) ) );
+
+}
+
+/* The 32x32-bit S-Box S2
+ * Input: a 32-bit input.
+ * Output: a 32-bit output of S2 box.
+ * See section 3.3.2
+ * https://www.gsma.com/aboutus/wp-content/uploads/2014/12/snow3gspec.pdf
+ * for details.
+ */
+
+u32 S2(u32 w)
+{
+ u8 r0=0, r1=0, r2=0, r3=0;
+ u8 sqw0 = SQ[ (u8)((w >> 24) & 0xff) ];
+ u8 sqw1 = SQ[ (u8)((w >> 16) & 0xff) ];
+ u8 sqw2 = SQ[ (u8)((w >> 8) & 0xff) ];
+ u8 sqw3 = SQ[ (u8)((w) & 0xff) ];
+
+
+ r0 = ( ( MULx( sqw0 , 0x69) ) ^
+ ( sqw1 ) ^
+ ( sqw2 ) ^
+ ( (MULx( sqw3, 0x69)) ^ sqw3 )
+ );
+
+
+ r1 = ( ( ( MULx( sqw0 , 0x69) ) ^ sqw0 ) ^
+ ( MULx(sqw1, 0x69) ) ^
+ ( sqw2 ) ^
+ ( sqw3 )
+ );
+
+ r2 = ( ( sqw0 ) ^
+ ( ( MULx( sqw1 , 0x69) ) ^ sqw1 ) ^
+ ( MULx(sqw2, 0x69) ) ^
+ ( sqw3 )
+ );
+
+ r3 = ( ( sqw0 ) ^
+ ( sqw1 ) ^
+ ( ( MULx( sqw2 , 0x69) ) ^ sqw2 ) ^
+ ( MULx( sqw3, 0x69) )
+ );
+
+
+ return ( ( ((u32)r0) << 24 ) | ( ((u32)r1) << 16 ) | ( ((u32)r2) << 8 ) |
+ ( ((u32)r3) ) );
+
+}
+
+/* Clocking LFSR in initialization mode.
+ * LFSR Registers S0 to S15 are updated as the LFSR receives a single clock.
+ * Input F: a 32-bit word comes from output of FSM.
+ * See section 3.4.4
+ * https://www.gsma.com/aboutus/wp-content/uploads/2014/12/snow3gspec.pdf
+ * for details.
+ */
+
+void ClockLFSRInitializationMode(u32 F)
+{
+ u32 v = ( ( (LFSR_S0 << 8) & 0xffffff00 ) ^
+ ( MULalpha( (u8)((LFSR_S0>>24) & 0xff) ) ) ^
+ ( LFSR_S2 ) ^
+ ( (LFSR_S11 >> 8) & 0x00ffffff ) ^
+ ( DIValpha( (u8)( ( LFSR_S11) & 0xff ) ) ) ^
+ ( F )
+ );
+
+ LFSR_S0 = LFSR_S1;
+ LFSR_S1 = LFSR_S2;
+ LFSR_S2 = LFSR_S3;
+ LFSR_S3 = LFSR_S4;
+ LFSR_S4 = LFSR_S5;
+ LFSR_S5 = LFSR_S6;
+ LFSR_S6 = LFSR_S7;
+ LFSR_S7 = LFSR_S8;
+ LFSR_S8 = LFSR_S9;
+ LFSR_S9 = LFSR_S10;
+ LFSR_S10 = LFSR_S11;
+ LFSR_S11 = LFSR_S12;
+ LFSR_S12 = LFSR_S13;
+ LFSR_S13 = LFSR_S14;
+ LFSR_S14 = LFSR_S15;
+ LFSR_S15 = v;
+}
+
+/* Clocking LFSR in keystream mode.
+ * LFSR Registers S0 to S15 are updated as the LFSR receives a single clock.
+ * See section 3.4.5
+ * https://www.gsma.com/aboutus/wp-content/uploads/2014/12/snow3gspec.pdf
+ * for details.
+ */
+
+void ClockLFSRKeyStreamMode()
+{
+ u32 v = ( ( (LFSR_S0 << 8) & 0xffffff00 ) ^
+ ( MULalpha( (u8)((LFSR_S0>>24) & 0xff) ) ) ^
+ ( LFSR_S2 ) ^
+ ( (LFSR_S11 >> 8) & 0x00ffffff ) ^
+ ( DIValpha( (u8)( ( LFSR_S11) & 0xff ) ) )
+ );
+
+
+ LFSR_S0 = LFSR_S1;
+ LFSR_S1 = LFSR_S2;
+ LFSR_S2 = LFSR_S3;
+ LFSR_S3 = LFSR_S4;
+ LFSR_S4 = LFSR_S5;
+ LFSR_S5 = LFSR_S6;
+ LFSR_S6 = LFSR_S7;
+ LFSR_S7 = LFSR_S8;
+ LFSR_S8 = LFSR_S9;
+ LFSR_S9 = LFSR_S10;
+ LFSR_S10 = LFSR_S11;
+ LFSR_S11 = LFSR_S12;
+ LFSR_S12 = LFSR_S13;
+ LFSR_S13 = LFSR_S14;
+ LFSR_S14 = LFSR_S15;
+ LFSR_S15 = v;
+}
+
+/* Clocking FSM.
+ * Produces a 32-bit word F.
+ * Updates FSM registers R1, R2, R3.
+ * See Section 3.4.6 of
+ * https://www.gsma.com/aboutus/wp-content/uploads/2014/12/snow3gspec.pdf
+ * for details.
+ */
+
+u32 ClockFSM()
+{
+ u32 F = ( ( LFSR_S15 + FSM_R1 ) & 0xffffffff ) ^ FSM_R2 ;
+ u32 r = ( FSM_R2 + ( FSM_R3 ^ LFSR_S5 ) ) & 0xffffffff ;
+ FSM_R3 = S2(FSM_R2);
+ FSM_R2 = S1(FSM_R1);
+ FSM_R1 = r;
+ return F;
+}
+
+/* Initialization.
+ * Input k[4]: Four 32-bit words making up 128-bit key.
+ * Input IV[4]: Four 32-bit words making 128-bit initialization variable.
+ * Output: All the LFSRs and FSM are initialized for key generation.
+ * See Section 4.1 of
+ * https://www.gsma.com/aboutus/wp-content/uploads/2014/12/snow3gspec.pdf
+ * for details.
+ */
+
+void Initialize(u32 k[4], u32 IV[4])
+{
+ u8 i=0;
+ u32 F = 0x0;
+ LFSR_S15 = k[3] ^ IV[0];
+ LFSR_S14 = k[2];
+ LFSR_S13 = k[1];
+ LFSR_S12 = k[0] ^ IV[1];
+ LFSR_S11 = k[3] ^ 0xffffffff;
+ LFSR_S10 = k[2] ^ 0xffffffff ^ IV[2];
+ LFSR_S9 = k[1] ^ 0xffffffff ^ IV[3];
+ LFSR_S8 = k[0] ^ 0xffffffff;
+ LFSR_S7 = k[3];
+ LFSR_S6 = k[2];
+ LFSR_S5 = k[1];
+ LFSR_S4 = k[0];
+ LFSR_S3 = k[3] ^ 0xffffffff;
+ LFSR_S2 = k[2] ^ 0xffffffff;
+ LFSR_S1 = k[1] ^ 0xffffffff;
+ LFSR_S0 = k[0] ^ 0xffffffff;
+ FSM_R1 = 0x0;
+ FSM_R2 = 0x0;
+ FSM_R3 = 0x0;
+
+ for(i=0;i<32;i++)
+ {
+ F = ClockFSM();
+ ClockLFSRInitializationMode(F);
+ }
+}
+
+
+/* Generation of Keystream.
+ * input n: number of 32-bit words of keystream.
+ * input z: space for the generated keystream, assumes
+ * memory is allocated already.
+ * output: generated keystream which is filled in z
+ * See section 4.2 of
+ * https://www.gsma.com/aboutus/wp-content/uploads/2014/12/snow3gspec.pdf
+ * for details.
+ */
+
+void GenerateKeystream(u32 n, u32 *ks)
+{
+ u32 t = 0;
+ u32 F = 0x0;
+ ClockFSM(); /* Clock FSM once. Discard the output. */
+ ClockLFSRKeyStreamMode(); /* Clock LFSR in keystream mode once. */
+
+ for ( t=0; t<n; t++)
+ {
+ F = ClockFSM();/* STEP 1 */
+ ks[t] = F ^ LFSR_S0; /* STEP 2 */
+
+ /* Note that ks[t] corresponds to z_{t+1} in section 4.2 of
+ * https://www.gsma.com/aboutus/wp-content/uploads/2014/12/snow3gspec.pdf
+ */
+
+ ClockLFSRKeyStreamMode(); /* STEP 3 */
+ }
+}
+/*------------------------------------------------------------------*/
diff --git a/src/common/thread_pool.c b/src/common/thread_pool.c
new file mode 100644
index 0000000..aa44e31
--- /dev/null
+++ b/src/common/thread_pool.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2003-2018, Great Software Laboratory Pvt. Ltd.
+ * Copyright (c) 2017 Intel Corporation
+ * Copyright (c) 2019, Infosys Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include <unistd.h>
+#include "thread_pool.h"
+#include "tpool_queue.h"
+
+struct Job *create_job(JobFunction function, void *arg)
+{
+ struct Job *job;
+ job = (struct Job *)malloc(sizeof(struct Job));
+ if(job == NULL) {
+#ifdef DEBUG
+ log_msg(LOG_ERROR, "failed to allocate memory\n");
+#endif
+ return NULL;
+ }
+ job->function = function;
+ job->arg = arg;
+ return job;
+}
+
+static void *worker_thread(void *userdata)
+{
+ void *arg;
+ struct Job *job;
+ JobFunction function;
+ struct thread_pool *pool;
+
+ pool = (struct thread_pool *)userdata;
+
+ while(1) {
+ pthread_mutex_lock(&pool->queue_mutex);
+
+ /* waiting until dispatch thread signals for new job */
+ pthread_cond_wait(&pool->job_received, &pool->queue_mutex);
+ job = queue_pop_head(pool->job_queue);
+ pthread_mutex_unlock(&pool->queue_mutex);
+
+ if(job != NULL) {
+ function = job->function;
+ arg = job->arg;
+ free(job);
+
+ /* atomically updating idle_threads */
+ __sync_fetch_and_sub(&pool->idle_threads, 1);
+
+ function(arg);
+
+ __sync_fetch_and_add(&pool->idle_threads, 1);
+ }
+ }
+ return NULL;
+}
+
+/* If queue has pending jobs and
+ * thread is idle then signal the thread
+ * to process the job
+ */
+static void *dispatch_if_idle(void *userdata)
+{
+ struct thread_pool *pool;
+
+ pool = (struct thread_pool *)userdata;
+
+ while(1) {
+ if((pool->idle_threads > 0) &&
+ pool->job_queue->length > 0 ) {
+ pthread_cond_signal(&pool->job_received);
+ } else usleep(10);
+ }
+ return NULL;
+}
+
+/* creates a thread and pushes into queue */
+static int spawn_thread(struct thread_pool *pool)
+{
+ int status;
+ pthread_t thread;
+
+ status = pthread_create(&thread, NULL, worker_thread, pool);
+ if(status < 0)
+ return status;
+
+ queue_push_tail(pool->thread_queue, &thread);
+
+ return 0;
+}
+
+/* pushes job into queue */
+int insert_job(struct thread_pool *pool, JobFunction function, void *userdata)
+{
+ struct Job *job;
+
+ if(pool == NULL)
+ return -1;
+
+ job = create_job(function, userdata);
+ if(job == NULL)
+ return -ENOMEM;
+
+ pthread_mutex_lock(&pool->queue_mutex);
+ queue_push_tail(pool->job_queue, job);
+ pthread_mutex_unlock(&pool->queue_mutex);
+
+ return 0;
+}
+
+struct thread_pool *thread_pool_new(int count)
+{
+ int i, status;
+ pthread_t thread;
+ struct thread_pool *pool;
+
+ pool = (struct thread_pool *)malloc(sizeof(struct thread_pool));
+ if(pool == NULL) {
+#ifdef DEBUG
+ log_msg(LOG_ERROR, "failed to allocate memory\n");
+#endif
+ errno = ENOMEM;
+ return NULL;
+ }
+ pool->idle_threads = count;
+ pool->job_queue = queue_new();
+ pool->thread_queue = queue_new();
+
+ pthread_mutex_init(&pool->queue_mutex, NULL);
+ pthread_cond_init(&pool->job_received, NULL);
+
+ status = pthread_create(&thread, NULL, dispatch_if_idle, pool);
+ if(status < 0) {
+#ifdef DEBUG
+ log_msg(LOG_ERROR, "failed to spawn dispatch thread, stopping\n");
+#endif
+ return NULL;
+ }
+ pool->dispatch_thread = thread;
+
+ i = 0;
+ while(i < count)
+ if (spawn_thread(pool) == 0)
+ i++;
+
+ return pool;
+}
+
+int thread_pool_destroy(struct thread_pool *pool)
+{
+ pthread_t *thread;
+
+ if(pool == NULL)
+ return -1;
+
+ pthread_cancel(pool->dispatch_thread);
+ while((thread = queue_pop_head(pool->job_queue)) != NULL) {
+ pthread_cancel(*thread);
+ }
+
+ queue_destroy(pool->job_queue, free);
+ queue_destroy(pool->thread_queue, NULL);
+ pthread_mutex_destroy(&pool->queue_mutex);
+ pthread_cond_destroy(&pool->job_received);
+
+ free(pool);
+ return 0;
+}
+
+
diff --git a/src/common/tpool_queue.c b/src/common/tpool_queue.c
new file mode 100644
index 0000000..f8e0092
--- /dev/null
+++ b/src/common/tpool_queue.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2003-2018, Great Software Laboratory Pvt. Ltd.
+ * Copyright (c) 2017 Intel Corporation
+ * Copyright (c) 2019, Infosys Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "thread_pool.h"
+#include "tpool_queue.h"
+
+/* allocates memory for node and initialize it */
+static struct node *createnode(void *data)
+{
+ struct node *entry;
+
+ entry = (struct node *)malloc(sizeof(struct node));
+ if(entry == NULL) {
+#ifdef DEBUG
+ log_msg(LOG_ERROR, "failed to allocate memory\n");
+#endif
+ return NULL;
+ }
+
+ entry->data = data;
+ entry->next = NULL;
+
+ return entry;
+}
+
+/* push data to queue tail */
+int queue_push_tail(struct Queue *queue, void *data)
+{
+ struct node *entry;
+
+ if(queue == NULL)
+ return -1;
+
+ entry = createnode(data);
+ if(entry == NULL) {
+ return -ENOMEM;
+ }
+
+ /* For empty queue */
+ if(queue->head == NULL)
+ queue->head = entry;
+ else
+ queue->tail->next = entry;
+ queue->tail = entry;
+
+ /* atomic increment */
+ __sync_fetch_and_add(&queue->length, 1);
+ return 0;
+}
+
+/* removes head and return its data */
+void *queue_pop_head(struct Queue *queue)
+{
+ void *data;
+ struct node *entry;
+
+ if(queue == NULL || queue->length == 0)
+ return NULL;
+
+ if(queue->head == NULL) {
+ return NULL;
+ }
+
+ entry = queue->head;
+ queue->head = queue->head->next;
+ data = entry->data;
+ /* atomic decrement */
+ __sync_fetch_and_sub(&queue->length, 1);
+ free(entry);
+
+ return data;
+}
+
+int queue_get_length(struct Queue *queue)
+{
+ if (queue == NULL)
+ return 0;
+
+ return queue->length;
+}
+
+struct Queue *queue_new()
+{
+ struct Queue *queue;
+
+ queue = (struct Queue *)malloc(sizeof(struct Queue));
+ if(queue == NULL) {
+#ifdef DEBUG
+ log_msg(LOG_ERROR, "failed to allocate memory\n");
+#endif
+ return NULL;
+ }
+
+ queue->length = 0;
+ queue->head = NULL;
+ queue->tail = NULL;
+
+ return queue;
+}
+
+void queue_destroy(struct Queue *queue, QueueDataFreeFunc function)
+{
+ struct node *tmp;
+
+ if(queue == NULL || queue->length == 0)
+ {
+ free(queue);
+ return;
+ }
+
+ if(queue->head == NULL)
+ free(queue);
+ else {
+ tmp = queue->head;
+ while(queue->head != NULL) {
+ tmp = queue->head->next;
+ if (function != NULL)
+ function(queue->head->data);
+ free(queue->head);
+ queue->head=tmp;
+ }
+ }
+
+}
+
+