changeset 1359:09f94b1bedc3

Merge new proposed changes
author Sebastien Decugis <sdecugis@freediameter.net>
date Sun, 02 Jun 2019 22:39:28 +0800
parents cf411b1dcbbb (diff) 23db8abdccda (current diff)
children 7f5aa6bb3642
files
diffstat 11 files changed, 469 insertions(+), 187 deletions(-) [+]
line wrap: on
line diff
--- a/doc/acl_wl.conf.sample	Sun Jun 02 22:34:59 2019 +0800
+++ b/doc/acl_wl.conf.sample	Sun Jun 02 22:39:28 2019 +0800
@@ -3,6 +3,11 @@
 # This extension is meant to allow connection from remote peers, without actively
 # maintaining this connection ourselves (as it would be the case by declaring the 
 # peer in a ConnectPeer directive).
+#
+# This extension supports configuration reload at runtime. Send
+# signal SIGUSR1 to the process to cause the process to reload its
+# config.
+#
 # The format of this file is very simple. It contains a list of peer names
 # separated by spaces or newlines. 
 #
--- a/extensions/acl_wl/acl_wl.c	Sun Jun 02 22:34:59 2019 +0800
+++ b/extensions/acl_wl/acl_wl.c	Sun Jun 02 22:39:28 2019 +0800
@@ -37,8 +37,17 @@
  * Whitelist extension for freeDiameter.
  */
 
+#include <pthread.h>
+#include <signal.h>
+
 #include "acl_wl.h"
 
+static pthread_rwlock_t acl_wl_lock;
+
+#define MODULE_NAME "acl_wl"
+
+static char *acl_wl_config_file;
+
 /* The validator function */
 static int aw_validate(struct peer_info * info, int * auth, int (**cb2)(struct peer_info *))
 {
@@ -53,9 +62,20 @@
 	
 	/* Default to unknown result */
 	*auth = 0;
-	
+
+        if (pthread_rwlock_rdlock(&acl_wl_lock) != 0) {
+		fd_log_notice("%s: read-lock failed, skipping handler", MODULE_NAME);
+		return 0;
+	}
+
 	/* Now search the peer in our tree */
 	CHECK_FCT( aw_tree_lookup(info->pi_diamid, &res) );
+
+        if (pthread_rwlock_unlock(&acl_wl_lock) != 0) {
+		fd_log_notice("%s: read-unlock failed after aw_tree_lookup, exiting", MODULE_NAME);
+		exit(1);
+	}
+
 	if (res < 0) {
 		/* The peer is not whitelisted */
 		return 0;
@@ -87,20 +107,82 @@
 	return 0;
 }
 
+static volatile int in_signal_handler = 0;
+
+/* signal handler */
+static void sig_hdlr(void)
+{
+	struct fd_list old_tree;
+
+	if (in_signal_handler) {
+		fd_log_error("%s: already handling a signal, ignoring new one", MODULE_NAME);
+		return;
+	}
+	in_signal_handler = 1;
+
+	if (pthread_rwlock_wrlock(&acl_wl_lock) != 0) {
+		fd_log_error("%s: locking failed, aborting config reload", MODULE_NAME);
+		return;
+	}
+
+	/* save old config in case reload goes wrong */
+	old_tree = tree_root;
+	fd_list_init(&tree_root, NULL);
+
+	if (aw_conf_handle(acl_wl_config_file) != 0) {
+		fd_log_error("%s: error reloading configuration, restoring previous configuration", MODULE_NAME);
+		aw_tree_destroy();
+		tree_root = old_tree;
+	} else {
+		struct fd_list new_tree;
+		new_tree = tree_root;
+		tree_root = old_tree;
+		aw_tree_destroy();
+		tree_root = new_tree;
+	}
+
+	if (pthread_rwlock_unlock(&acl_wl_lock) != 0) {
+		fd_log_error("%s: unlocking failed after config reload, exiting", MODULE_NAME);
+		exit(1);
+	}
+
+	fd_log_notice("%s: reloaded configuration", MODULE_NAME);
+
+	in_signal_handler = 0;
+}
+
+
 /* entry point */
 static int aw_entry(char * conffile)
 {
 	TRACE_ENTRY("%p", conffile);
 	CHECK_PARAMS(conffile);
-	
+
+	acl_wl_config_file = conffile;
+
+        pthread_rwlock_init(&acl_wl_lock, NULL);
+
+        if (pthread_rwlock_wrlock(&acl_wl_lock) != 0) {
+                fd_log_notice("%s: write-lock failed, aborting", MODULE_NAME);
+                return EDEADLK;
+        }
+
 	/* Parse configuration file */
 	CHECK_FCT( aw_conf_handle(conffile) );
-	
+
 	TRACE_DEBUG(INFO, "Extension ACL_wl initialized with configuration: '%s'", conffile);
 	if (TRACE_BOOL(ANNOYING)) {
 		aw_tree_dump();
 	}
-	
+
+	if (pthread_rwlock_unlock(&acl_wl_lock) != 0) {
+		fd_log_notice("%s: write-unlock failed, aborting", MODULE_NAME);
+		return EDEADLK;
+	}
+
+	/* Register reload callback */
+	CHECK_FCT(fd_event_trig_regcb(SIGUSR1, MODULE_NAME, sig_hdlr));
+
 	/* Register the validator function */
 	CHECK_FCT( fd_peer_validate_register ( aw_validate ) );
 
@@ -114,4 +196,4 @@
 	aw_tree_destroy();
 }
 
-EXTENSION_ENTRY("acl_wl", aw_entry);
+EXTENSION_ENTRY(MODULE_NAME, aw_entry);
--- a/extensions/acl_wl/acl_wl.h	Sun Jun 02 22:34:59 2019 +0800
+++ b/extensions/acl_wl/acl_wl.h	Sun Jun 02 22:39:28 2019 +0800
@@ -43,6 +43,8 @@
  
 #include <freeDiameter/extension.h>
 
+extern struct fd_list tree_root;
+
 /* Parse the configuration file */
 int aw_conf_handle(char * conffile);
 
--- a/extensions/acl_wl/aw_conf.l	Sun Jun 02 22:34:59 2019 +0800
+++ b/extensions/acl_wl/aw_conf.l	Sun Jun 02 22:39:28 2019 +0800
@@ -35,7 +35,7 @@
 
 /* Lex extension's configuration parser.
  *
- * The configuration file contains a default priority, and a list of peers with optional overwite priority.
+ * The configuration file contains a default priority, and a list of peers with optional overwrite priority.
  * -- see the app_test.conf.sample file for more detail.
  */
 
--- a/extensions/acl_wl/aw_conf.y	Sun Jun 02 22:34:59 2019 +0800
+++ b/extensions/acl_wl/aw_conf.y	Sun Jun 02 22:39:28 2019 +0800
@@ -57,6 +57,7 @@
 
 /* Forward declaration */
 int yyparse(char * conffile);
+void aw_confrestart(FILE *input_file);
 
 static int fqdn_added = 0;
 
@@ -74,19 +75,20 @@
 	if (aw_confin == NULL) {
 		ret = errno;
 		fd_log_debug("Unable to open extension configuration file %s for reading: %s", conffile, strerror(ret));
-		TRACE_DEBUG (INFO, "Error occurred, message logged -- configuration file.");
+		TRACE_DEBUG (INFO, "acl_wl: Error occurred, message logged -- configuration file.");
 		return ret;
 	}
 
+	aw_confrestart(aw_confin);
 	ret = yyparse(conffile);
 
 	fclose(aw_confin);
 
 	if (ret != 0) {
-		TRACE_DEBUG (INFO, "Unable to parse the configuration file.");
+		TRACE_DEBUG (INFO, "acl_wl: Unable to parse the configuration file.");
 		return EINVAL;
 	} else {
-		TRACE_DEBUG(FULL, "Read %d FQDN entries successfully.", fqdn_added);
+		TRACE_DEBUG(FULL, "acl_wl: Read %d FQDN entries successfully.", fqdn_added);
 	}
 	
 	return 0;
@@ -98,7 +100,7 @@
 /* Function to report the errors */
 void yyerror (YYLTYPE *ploc, char * conffile, char const *s)
 {
-	TRACE_DEBUG(INFO, "Error in configuration parsing");
+	TRACE_DEBUG(INFO, "acl_wl: Error in configuration parsing");
 	
 	if (ploc->first_line != ploc->last_line)
 		fd_log_debug("%s:%d.%d-%d.%d : %s", conffile, ploc->first_line, ploc->first_column, ploc->last_line, ploc->last_column, s);
@@ -130,11 +132,11 @@
 			| conffile FQDN
 			{
 				fqdn_added++;
-				TRACE_DEBUG(FULL, "Added FQDN: %s", $2);
+				TRACE_DEBUG(FULL, "acl_wl: Added FQDN: %s", $2);
 			}
 			| conffile LEX_ERROR
 			{
-				yyerror(&yylloc, conffile, "An error occurred while parsing the configuration file");
+				yyerror(&yylloc, conffile, "acl_wl: An error occurred while parsing the configuration file");
 				return EINVAL;
 			}
 			;
--- a/extensions/acl_wl/aw_tree.c	Sun Jun 02 22:34:59 2019 +0800
+++ b/extensions/acl_wl/aw_tree.c	Sun Jun 02 22:39:28 2019 +0800
@@ -69,9 +69,9 @@
 };
 
 /* The root of the tree */
-static struct fd_list tree_root = FD_LIST_INITIALIZER(tree_root);
+struct fd_list tree_root = FD_LIST_INITIALIZER(tree_root);
 
-/* Note: we don't need to lock, since we add only when parsing the conf, and then read only */
+/* Note: we lock accesses to the tree with acl_wl_lock because of config reload */
 
 
 /* The parsed name */
--- a/extensions/dict_json/CMakeLists.txt	Sun Jun 02 22:34:59 2019 +0800
+++ b/extensions/dict_json/CMakeLists.txt	Sun Jun 02 22:39:28 2019 +0800
@@ -6,11 +6,12 @@
 # We use JSONCPP and JSON-Schema to parse and validate JSON files
 PKG_CHECK_MODULES(JSONCPP REQUIRED jsoncpp)
 PKG_CHECK_MODULES(JSON_SCHEMA REQUIRED json-schema)
+PKG_CHECK_MODULES(PCRECPP REQUIRED libpcrecpp)
 
 # List of source files
 SET(DICT_JSON_SRC
 	dict_json.cc
-	dict_json_dict_schema.cc
+	${CMAKE_CURRENT_BINARY_DIR}/dict_json_dict_schema.cc
 )
 
 INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
@@ -28,6 +29,14 @@
 ADD_EXECUTABLE(dict-json-diff dict-json-diff.cc)
 TARGET_LINK_LIBRARIES(dict-json-diff ${JSONCPP_LIBRARIES} ${JSON_SCHEMA_STATIC_LIBRARIES})
 
+ADD_EXECUTABLE(json-schema-to-c json-schema-to-c.cc)
+TARGET_LINK_LIBRARIES(json-schema-to-c ${JSONCPP_LIBRARIES} ${JSON_SCHEMA_STATIC_LIBRARIES} ${PCRECPP_LIBRARIES})
+
+ADD_CUSTOM_COMMAND(
+	OUTPUT dict_json_dict_schema.cc
+	COMMAND json-schema-to-c ${CMAKE_CURRENT_SOURCE_DIR}/dict_json_dict_schema.json ${CMAKE_CURRENT_BINARY_DIR}/dict_json_dict_schema.cc
+	DEPENDS dict_json_dict_schema.json
+)
 
 ####
 ## INSTALL section ##
@@ -38,6 +47,3 @@
 INSTALL(TARGETS dict-json-diff
 	RUNTIME DESTINATION ${INSTALL_DAEMON_SUFFIX}
 	COMPONENT freeDiameter-dictionary-json)
-
-# dict_json_dict_schema.cc is created from dict_json_dict_schema.json
-# the tool for that is not yet open source, but the conversion is straightforward
--- a/extensions/dict_json/dict_json_dict_schema.cc	Sun Jun 02 22:34:59 2019 +0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,164 +0,0 @@
-const char * dict_json_dict_schema = "\
-{ \n\
-    \"definitions\": { \n\
-        \"content\": { \n\
-            \"type\": \"array\", \n\
-            \"items\": { \n\
-                \"type\": \"object\", \n\
-                \"additionalProperties\": false, \n\
-                \"required\": [ \"AVP\" ], \n\
-                \"properties\": { \n\
-                    \"AVP\": { \"type\": \"string\" }, \n\
-                    \"Vendor\": { \"$ref\": \"#/definitions/unsigned-integer\" }, \n\
-                    \"First\": { \"type\": \"boolean\" }, \n\
-                    \"Min\": { \"$ref\": \"#/definitions/unsigned-integer\" }, \n\
-                    \"Max\": { \"anyOf\": [ { \"type\": \"integer\" }, { \"enum\": [ \"unbounded\" ] } ] } \n\
-                } \n\
-            } \n\
-        }, \n\
- \n\
-        \"identifier\": { \"type\": \"string\", \"pattern\": \"^[[:print:]]+$\" }, \n\
-        \"type\": { \n\
-            \"enum\": [ \n\
-                \"Address\", \n\
-                \"DiameterIdentity\", \n\
-                \"DiameterURI\", \n\
-                \"Enumerated\", \n\
-                \"Float32\", \n\
-                \"Float64\", \n\
-                \"Grouped\", \n\
-                \"Integer32\", \n\
-                \"Integer64\", \n\
-                \"IPFilterRule\", \n\
-                \"OctetString\", \n\
-                \"Time\", \n\
-                \"Unsigned32\", \n\
-                \"Unsigned64\", \n\
-                \"UTF8String\" \n\
-            ] \n\
-        }, \n\
-        \"unsigned-integer\": { \"type\": \"integer\", \"minimum\": 0 } \n\
-    }, \n\
-     \n\
-    \"type\": \"object\", \n\
-    \"additionalProperties\": false, \n\
-    \"properties\": { \n\
-        \"Vendors\": { \n\
-            \"type\": \"array\", \n\
-            \"items\": { \n\
-                \"type\": \"object\", \n\
-                \"additionalProperties\": false, \n\
-                \"required\": [ \"Code\", \"Name\" ], \n\
-                \"properties\": { \n\
-                    \"Code\": { \"$ref\": \"#/definitions/unsigned-integer\" }, \n\
-                    \"Name\": { \"$ref\": \"#/definitions/identifier\" } \n\
-                } \n\
-            } \n\
-        }, \n\
-        \"Types\": { \n\
-            \"type\": \"array\", \n\
-            \"items\": { \n\
-                \"type\": \"object\", \n\
-                \"additionalProperties\": false, \n\
-                \"required\": [ \"Name\", \"Base\" ], \n\
-                \"properties\": { \n\
-                    \"Name\": { \"type\": \"string\" }, \n\
-                    \"Base\": { \"type\": \"string\" } \n\
-                } \n\
-            } \n\
-        }, \n\
-        \"AVPs\": { \n\
-            \"type\": \"array\", \n\
-            \"items\": { \n\
-                \"type\": \"object\", \n\
-                \"additionalProperties\": false, \n\
-                \"required\": [ \"Code\", \"Name\", \"Type\" ], \n\
-                \"properties\": { \n\
-                    \"Code\": { \"$ref\": \"#/definitions/unsigned-integer\" }, \n\
-                    \"Vendor\": { \"$ref\": \"#/definitions/unsigned-integer\" }, \n\
-                    \"Name\": { \"$ref\": \"#/definitions/identifier\" }, \n\
-                    \"Flags\": { \n\
-                        \"type\": \"object\", \n\
-                        \"additionalProperties\": false, \n\
-                        \"properties\": { \n\
-                            \"Must\": { \"type\": \"string\", \"pattern\": \"^[VMP]*$\" }, \n\
-                            \"MustNot\": { \"type\": \"string\", \"pattern\": \"^[VMP]*$\" } \n\
-                        } \n\
-                    }, \n\
-                    \"Type\": { \"$ref\": \"#/definitions/identifier\" }, \n\
-                    \"EnumValues\": { \n\
-                        \"type\": \"array\", \n\
-                        \"items\": { \n\
-                            \"type\": \"object\", \n\
-                            \"additionalProperties\": false, \n\
-                            \"required\": [ \"Code\", \"Name\" ], \n\
-                            \"properties\": { \n\
-                                \"Code\": { \"anyOf\": [ { \"type\": \"integer\" }, { \"type\": \"number\" }, { \"type\": \"string\" } ] }, \n\
-                                \"Name\": { \"type\": \"string\", \"pattern\": \"^[[:print:]]*$\" } \n\
-                            } \n\
-                        } \n\
-                    } \n\
-                } \n\
-            } \n\
-        }, \n\
-        \"Applications\": { \n\
-            \"type\": \"array\", \n\
-            \"items\": { \n\
-                \"type\": \"object\", \n\
-                \"additionalProperties\": false, \n\
-                \"required\": [ \"Code\", \"Name\" ], \n\
-                \"properties\": { \n\
-                    \"Code\": { \"$ref\": \"#/definitions/unsigned-integer\" }, \n\
-                    \"Name\": { \"$ref\": \"#/definitions/identifier\" } \n\
-                } \n\
-            } \n\
-        }, \n\
-        \"Commands\": { \n\
-            \"type\": \"array\", \n\
-            \"items\": { \n\
-                \"type\": \"object\", \n\
-                \"additionalProperties\": false, \n\
-                \"required\": [ \"Code\", \"Name\" ], \n\
-                \"properties\": { \n\
-                    \"Code\": { \"$ref\": \"#/definitions/unsigned-integer\" }, \n\
-                    \"Name\": { \"$ref\": \"#/definitions/identifier\" }, \n\
-                    \"Application\": { \"$ref\": \"#/definitions/identifier\" }, \n\
-                    \"Flags\": { \n\
-                        \"type\": \"object\", \n\
-                        \"additionalProperties\": false, \n\
-                        \"properties\": { \n\
-                            \"Must\": { \"type\": \"string\", \"pattern\": \"^[RPE]*$\" }, \n\
-                            \"MustNot\": { \"type\": \"string\", \"pattern\": \"^[RPET]*$\" } \n\
-                        } \n\
-                    } \n\
-                } \n\
-            } \n\
-        }, \n\
-        \"CommandRules\": { \n\
-            \"type\": \"array\", \n\
-            \"items\": { \n\
-                \"type\": \"object\", \n\
-                \"additionalProperties\": false, \n\
-                \"required\": [ \"Command\", \"Content\" ], \n\
-                \"properties\": { \n\
-                    \"Command\": { \"type\": \"string\", \"minimum\": 0 }, \n\
-                    \"Content\": { \"$ref\": \"#/definitions/content\" } \n\
-                } \n\
-            } \n\
-        }, \n\
-        \"AVPRules\": { \n\
-            \"type\": \"array\", \n\
-            \"items\": { \n\
-                \"type\": \"object\", \n\
-                \"additionalProperties\": false, \n\
-                \"required\": [ \"AVP\", \"Content\" ], \n\
-                \"properties\": { \n\
-                    \"AVP\": { \"type\": \"string\" }, \n\
-                    \"Vendor\": { \"type\": \"integer\", \"minimum\" : 0 }, \n\
-                    \"Content\": { \"$ref\": \"#/definitions/content\" } \n\
-                } \n\
-            } \n\
-        } \n\
-    } \n\
-} \n\
-";
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/extensions/dict_json/json-schema-to-c.cc	Sun Jun 02 22:39:28 2019 +0800
@@ -0,0 +1,350 @@
+/**********************************************************************************************************
+ * Software License Agreement (BSD License)                                                               *
+ * Author: Thomas Klausner <tk@giga.or.at>                                                                *
+ *                                                                                                        *
+ * Copyright (c) 2016, 2017, 2019 Thomas Klausner                                                         *
+ * All rights reserved.                                                                                   *
+ *                                                                                                        *
+ * Written under contract by nfotex IT GmbH, http://nfotex.com/                                           *
+ *                                                                                                        *
+ * Redistribution and use of this software in source and binary forms, with or without modification, are  *
+ * permitted provided that the following conditions are met:                                              *
+ *                                                                                                        *
+ * * Redistributions of source code must retain the above                                                 *
+ *   copyright notice, this list of conditions and the                                                    *
+ *   following disclaimer.                                                                                *
+ *                                                                                                        *
+ * * 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 "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 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 <errno.h>
+#include <getopt.h>
+#include <inttypes.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <json/SchemaValidator.h>
+
+[[noreturn]]
+void usage(char *prg, int exit_status) {
+    FILE *f = (exit_status ? stderr : stdout);
+
+    fprintf(f, "Usage: %s [-hV] [-i include] [-N variable-name] [-n namespace] [-t type] json [output]\n", prg);
+    fprintf(f, "options:\n\
+  -h, --help              print this usage message and exit\n\
+  -i, --include FILE      include FILE in output C source file\n\
+  -n, --namespace NAME    specify namespace in which to define variable\n\
+  -N, --name NAME         specify name of variable to define\n\
+  --no-validate           don't validate against JSON meta schema (default)\n\
+  --type TYPE             specify type of variable (char * (default) or std::string)\n\
+  --validate              validate against JSON meta schema\n\
+  --validate-only         validate against JSON meta schema and exit (don't create C source)\n\
+");
+
+    exit(exit_status);
+}
+
+const char *OPTIONS = "hi:N:n:t:V";
+
+enum {
+    OPT_NO_VALIDATE = 256,
+    OPT_VALIDATE_ONLY
+};
+struct option options[] = {
+    { "help", no_argument, NULL, 'h' },
+    { "include", required_argument, NULL, 'i' },
+    { "name", required_argument, NULL, 'N' },
+    { "namespace", required_argument, NULL, 'n' },
+    { "no-validate", no_argument, NULL, OPT_NO_VALIDATE },
+    { "type", required_argument, NULL, 't' },
+    { "validate", no_argument, NULL, 'V' },
+    { "validate-only", no_argument, NULL, OPT_VALIDATE_ONLY },
+    { NULL, 0, NULL, 0 }
+};
+
+char *read_full_file (const char *filename, off_t max_size, off_t* size_ret, const char *desc) {
+    FILE *fp;
+    if ((fp = fopen (filename, "rb")) == NULL) {
+        fprintf (stderr, "couldn't open %s file [%s]: %d, %s\n", desc, filename, errno, strerror(errno));
+        return NULL;
+    }
+    struct stat stat_buf;
+    if (fstat (fileno(fp), &stat_buf) < 0) {
+        fprintf (stderr, "couldn't stat %s file [%s]: %d, %s\n", desc, filename, errno, strerror(errno));
+        fclose (fp);
+        return NULL;
+    }
+    off_t n = stat_buf.st_size;
+    if (max_size > 0 && n > max_size) {
+        fprintf (stderr, "%s file [%s] is larger than %lld bytes\n", desc, filename, (long long)max_size);
+        fclose (fp);
+        return NULL;
+    }
+    char *buf;
+    if ((buf = (char *) malloc ((size_t)n+1)) == NULL) {
+        fprintf (stderr, "error allocating %lld bytes for read of %s file [%s]\n", (long long)n, desc, filename);
+        fclose (fp);
+        return NULL;
+    }
+    if (fread (buf, 1, (size_t)n, fp) < (size_t) n) {
+        fprintf (stderr, "error reading %s file [%s]: %d, %s\n", desc, filename, errno, strerror(errno));
+        fclose (fp);
+        free (buf);
+        return NULL;
+    }
+
+    fclose (fp);
+    buf[n] = '\0';
+    if (size_ret != NULL)
+        *size_ret = n;
+    return buf;
+}
+
+int main (int argc, char **argv) {
+    char *name_space = NULL;
+    char *name = NULL;
+    bool free_name = false;
+    char default_type[] = "char *";
+    char *type = default_type;
+    bool validate = false;
+    bool convert = true;
+    char *include = NULL;
+
+    int c;
+    while ((c=getopt_long(argc, argv, OPTIONS, options, NULL)) != EOF) {
+        switch (c) {
+            case 'i':
+                include = optarg;
+                break;
+
+            case 'N':
+                name = optarg;
+                break;
+
+            case 'n':
+                name_space = optarg;
+                break;
+
+            case 't':
+                type = optarg;
+                break;
+
+            case 'V':
+                validate = true;
+                break;
+
+            case OPT_NO_VALIDATE:
+                validate = false;
+                break;
+
+            case OPT_VALIDATE_ONLY:
+                validate = true;
+                convert = false;
+                break;
+
+            case 'h':
+                usage(argv[0], 0);
+
+            default:
+                usage(argv[0], 1);
+        }
+    }
+
+    if (optind != argc - 2 && optind != argc - 1)
+        usage(argv[0], 1);
+
+    char *input = argv[optind];
+    char *output = NULL;
+    if (optind == argc -2) {
+        output = argv[optind+1];
+    }
+
+    char *str = read_full_file(input, 10*1024*1024, NULL, input);
+
+    Json::Reader reader;
+
+    Json::Value json;
+    if (!reader.parse(str, json)) {
+	fprintf(stderr, "%s: parse error: %s\n", input, reader.getFormattedErrorMessages().c_str());
+        exit(1);
+    }
+
+    if (validate) {
+        std::string error_message;
+        Json::SchemaValidator *validator;
+
+        try {
+            validator = Json::SchemaValidator::create_meta_validator();
+        }
+        catch (Json::SchemaValidator::Exception e) {
+            fprintf(stderr, "%s: can't create meta schema validator\n", argv[0]);
+            exit(1);
+        }
+
+        if (!validator->validate(json)) {
+            const std::vector<Json::SchemaValidator::Error> errors = validator->errors();
+
+            for (unsigned int i=0; i<errors.size(); i++)
+                fprintf(stderr, "%s:%s: %s\n", input, errors[i].path.c_str(), errors[i].message.c_str());
+            exit(1);
+        }
+
+        try {
+            Json::SchemaValidator v(json);
+        }
+        catch (Json::SchemaValidator::Exception e) {
+            fprintf(stderr, "%s: can't create schema validator: %s\n", argv[0], e.type_message().c_str());
+            for (auto error : e.errors) {
+                fprintf(stderr, "%s:%s: %s\n", input, error.path.c_str(), error.message.c_str());
+            }
+            exit(1);
+        }
+    }
+
+    if (!convert) {
+        exit(0);
+    }
+
+    FILE *fin = fopen(input, "r");
+    if (fin == NULL) {
+        fprintf(stderr, "%s: can't open schema file [%s]: %s\n", argv[0], input, strerror(errno));
+        exit(1);
+    }
+
+    FILE *fout;
+
+    if (output) {
+        fout = fopen(output, "w");
+        if (fout == NULL) {
+            fprintf(stderr, "%s: can't create output file [%s]: %s\n", argv[0], output, strerror(errno));
+            exit(1);
+        }
+    }
+    else {
+        fout = stdout;
+    }
+
+    if (name == NULL) {
+        char *base = basename(input);
+        char *end = strrchr(base, '.');
+        if (end == NULL) {
+            end = base + strlen(base);
+        }
+
+        name = strndup(base, static_cast<size_t>(end-base));
+
+        for (char *p = name; *p; p++) {
+            if ((*p >= 'A' && *p < 'Z') || (*p >= 'a' && *p < 'z') || *p == '_') {
+                continue;
+            }
+            else if (*p >= '0' && *p <= '9') {
+                if (p > name) {
+                    continue;
+                }
+            }
+            *p = '_';
+        }
+    }
+    else {
+        for (const char *p = name; *p; p++) {
+            if ((*p >= 'A' && *p < 'Z') || (*p >= 'a' && *p < 'z') || *p == '_') {
+                continue;
+            }
+            else if (*p >= '0' && *p <= '9') {
+                if (p > name) {
+                    continue;
+                }
+            }
+            else if (p[0] == ':' && p[1] == ':') {
+                p += 1;
+                continue;
+            }
+
+            fprintf(stderr, "%s: name [%s] is not a valid C identifier\n", argv[0], name);
+            exit(1);
+        }
+    }
+
+    if (include) {
+        fprintf(fout, "#include <%s>\n\n", include);
+    }
+
+    if (strcmp(type, "std::string") == 0) {
+        fputs("#include <string>\n\n", fout);
+    }
+
+    if (name_space) {
+        fprintf(fout, "namespace %s {\n\n", name_space);
+    }
+
+    fprintf(fout, "const %s %s = \"\\\n", type, name);
+
+    if (free_name) {
+        free(name);
+        name = NULL;
+    }
+
+    char line[8192];
+
+    while (fgets(line, sizeof(line), fin)) {
+        if (line[strlen(line)-1] == '\n')
+            line[strlen(line)-1] = '\0';
+
+        char *p = line;
+        char *end = line+strlen(line);
+        char *q;
+        do {
+            q = p + strcspn(p, "\"\\");
+            if (q < end) {
+                fprintf(fout, "%.*s\\%c", (int)(q-p), p, *q);
+                p=q+1;
+            }
+            else
+                fprintf(fout, "%s", p);
+        } while (q < end);
+
+        fputs(" \\n\\\n", fout);
+    }
+
+    fputs("\";\n", fout);
+
+    if (name_space) {
+        fputs("\n}\n", fout);
+    }
+
+    if (ferror(fin)) {
+        fprintf(stderr, "%s: read error on schema file [%s]: %s\n", argv[0], input, strerror(errno));
+        fclose(fout);
+        unlink(output);
+        exit(1);
+    }
+
+    fclose(fin);
+
+    if (ferror(fout)) {
+        fprintf(stderr, "%s: write error on output file [%s]: %s\n", argv[0], output, strerror(errno));
+        fclose(fout);
+        unlink(output);
+        exit(1);
+    }
+
+    fclose(fout);
+
+    exit(0);
+}
--- a/libfdcore/cnxctx.c	Sun Jun 02 22:34:59 2019 +0800
+++ b/libfdcore/cnxctx.c	Sun Jun 02 22:39:28 2019 +0800
@@ -1546,11 +1546,6 @@
 		tmp = gnutls_certificate_type_get_name (gnutls_certificate_type_get (session));
 		LOG_D("\t - Certificate Type: %s", tmp);
 
-		/* print the compression algorithm (if any)
-		*/
-		tmp = gnutls_compression_get_name (gnutls_compression_get (session));
-		LOG_D("\t - Compression: %s", tmp);
-
 		/* print the name of the cipher used.
 		* ie 3DES.
 		*/
--- a/tests/tests.h	Sun Jun 02 22:34:59 2019 +0800
+++ b/tests/tests.h	Sun Jun 02 22:39:28 2019 +0800
@@ -131,7 +131,9 @@
 }
 	
 
+#ifndef GNUTLS_VERSION_210
 GCRY_THREAD_OPTION_PTHREAD_IMPL;
+#endif /* GNUTLS_VERSION_210 */
 
 /* gnutls debug. */
 static void fd_gnutls_debug(int level, const char * str) {
@@ -213,8 +215,10 @@
 	parse_cmdline(argc, argv);
 	
 	/* Initialize gcrypt and gnutls */
+#ifndef GNUTLS_VERSION_210
 	(void) gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
 	(void) gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
+#endif /* GNUTLS_VERSION_210 */
 	CHECK( 0, gnutls_global_init());
 	/* Set gnutls debug level ? */
 	if (gnutls_debug) {
"Welcome to our mercurial repository"