Add helper functions for openssl error handling 52/66852/6
authorKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Thu, 21 Apr 2016 11:15:53 +0000 (13:15 +0200)
committerKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Tue, 26 Apr 2016 07:57:51 +0000 (09:57 +0200)
Change-Id: Ibc20d9e37bc2d90a92646e1115d9a1b63f5342e6

api/yaca/error.h
src/crypto.c
src/error.c [new file with mode: 0644]
src/internal.h

index 1e5ee16..5012c34 100644 (file)
@@ -41,6 +41,24 @@ enum __yaca_error_code {
        YACA_ERROR_SIGNATURE_INVALID = -7
 };
 
+// TODO disable debug function in release?
+
+/**
+ * @brief Debug callback type.
+ */
+typedef void (*yaca_debug_func)(const char*);
+
+/**
+ * @brief yaca_error_set_debug_func  Sets a current thread debug callback that will be called each
+ *                                   time an internal error occurs. A NULL terminated string with
+ *                                   location and description of the error will be passed as an
+ *                                   argument.
+ *
+ * @param[in] fn                     Function to set as internal error callback.
+ */
+void yaca_error_set_debug_func(yaca_debug_func fn);
+
+
 #ifdef __cplusplus
 } /* extern */
 #endif
index 2ffb10c..4cc313f 100644 (file)
@@ -22,6 +22,7 @@
 #include <openssl/crypto.h>
 #include <openssl/evp.h>
 #include <openssl/rand.h>
+#include <openssl/err.h>
 
 #include <yaca/crypto.h>
 #include <yaca/error.h>
@@ -46,6 +47,8 @@ API int yaca_init(void)
 
 API void yaca_exit(void)
 {
+       ERR_free_strings();
+       ERR_remove_thread_state(NULL);
        EVP_cleanup();
        CRYPTO_cleanup_all_ex_data();
 }
diff --git a/src/error.c b/src/error.c
new file mode 100644 (file)
index 0000000..140d1b4
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ *  Copyright (c) 2000 - 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  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
+ */
+/*
+ * @file       error.c
+ * @author     Krzysztof Jackiewicz (k.jackiewicz@samsung.com)
+ */
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include <openssl/err.h>
+
+#include <yaca/error.h>
+#include "internal.h"
+
+// TODO any better idea than to use __thread?
+static __thread yaca_debug_func debug_fn = NULL;
+static bool error_strings_loaded = false;
+
+API void yaca_error_set_debug_func(yaca_debug_func fn)
+{
+       debug_fn = fn;
+}
+
+// TODO use peeking function to intercept common errors
+//unsigned long ERR_peek_error();
+
+void error_dump(const char *file, int line, const char *function, int code)
+{
+       if (debug_fn == NULL)
+               return;
+
+       static const size_t BUF_SIZE = 512;
+       static const char ELLIPSIS[] = "...\n";
+       static const size_t ELLIPSIS_SIZE = sizeof(ELLIPSIS) / sizeof(ELLIPSIS[0]);
+       char buf[BUF_SIZE];
+       unsigned long err;
+       size_t written;
+
+       written = snprintf(buf, BUF_SIZE, "%s:%d %s() API error: %d\n", file, line, function, code);
+
+       while ((err = ERR_get_error()) != 0 && written < BUF_SIZE - 1) {
+               if (!error_strings_loaded) {
+                       /*
+                        * Both these functions are thread-safe as long as static locks are
+                        * installed according to doc so calling them twice won't break
+                        * anything and I don't want to use synchronization mechanisms
+                        * here.
+                        */
+                       ERR_load_crypto_strings();
+                       ERR_clear_error();
+                       error_strings_loaded = true;
+               }
+
+               ERR_error_string_n(err, buf + written, BUF_SIZE - written);
+               written = strlen(buf); /* I trust you, openssl */
+               if (written < BUF_SIZE - 1) {
+                       buf[written] = '\n';
+                       written++;
+               }
+       }
+
+       if (written >= BUF_SIZE - 1) {
+               strncpy(buf + BUF_SIZE - ELLIPSIS_SIZE, ELLIPSIS, ELLIPSIS_SIZE);
+               written = BUF_SIZE - 1;
+               ERR_clear_error();
+       }
+       buf[written] = '\0';
+
+       (*debug_fn)(buf);
+}
+
index 25f0edc..2b5dc9f 100644 (file)
@@ -94,4 +94,7 @@ int digest_get_algorithm(yaca_digest_algo_e algo, const EVP_MD **md);
 struct yaca_key_simple_s *key_get_simple(const yaca_key_h key);
 struct yaca_key_evp_s *key_get_evp(const yaca_key_h key);
 
+void error_dump(const char *file, int line, const char *function, int code);
+#define ERROR_DUMP(code) error_dump(__FILE__, __LINE__, __FUNCTION__, (code))
+
 #endif