From b85cf605f3b15dad8915c2916d0e0c834f16a7ea Mon Sep 17 00:00:00 2001
From: Vladimir Davydov <vdavydov@tarantool.org>
Date: Wed, 18 May 2022 10:44:03 +0300
Subject: [PATCH] box: add error code for SSLError

Applier uses box_error_code() to for better logging:
 - It remembers tha last raised error code and skips logging if the new
   error code is the same.
 - It logs "will retry every X seconds" only for retryable error codes
   (for example, ER_SYSTEM) while for non-retryable errors (for example,
   ER_PROC_LUA) the message isn't logged.

box_error_code() returns ER_PROC_LUA for SSLError, which is confusing
and would result in inconsistent logging in applier if we made SSLError
retryable. Let's add a separate error code for this error (ER_SSL) and
introduce a test case that checks that box_error_code() works as
expected for all kinds of errors.

Follow-up commit a7028dde8589 ("Add SSL iostream stub").
Needed for https://github.com/tarantool/tarantool-ee/issues/107

NO_DOC=internal
NO_CHANGELOG=internal
---
 src/box/errcode.h         |  1 +
 src/box/error.cc          |  3 +++
 src/lib/core/ssl_error.cc | 15 +++++++++++++
 src/lib/core/ssl_error.h  |  8 ++++++-
 test/box/error.result     |  1 +
 test/unit/CMakeLists.txt  |  2 +-
 test/unit/error.c         | 45 ++++++++++++++++++++++++++++++++++++++-
 test/unit/error.result    | 15 ++++++++++++-
 8 files changed, 86 insertions(+), 4 deletions(-)

diff --git a/src/box/errcode.h b/src/box/errcode.h
index 9438050c1d..ca6cb09c9e 100644
--- a/src/box/errcode.h
+++ b/src/box/errcode.h
@@ -295,6 +295,7 @@ struct errcode_record {
 	/*240 */_(ER_COMPLEX_FOREIGN_KEY_FAILED, "Foreign key constraint '%s' failed: %s") \
 	/*241 */_(ER_WRONG_SPACE_UPGRADE_OPTIONS, "Wrong space upgrade options: %s") \
 	/*242 */_(ER_NO_ELECTION_QUORUM,	"Not enough peers connected to start elections: %d out of minimal required %d")\
+	/*243 */_(ER_SSL,			"%s") \
 
 /*
  * !IMPORTANT! Please follow instructions at start of the file
diff --git a/src/box/error.cc b/src/box/error.cc
index 5097a076de..e0b916454b 100644
--- a/src/box/error.cc
+++ b/src/box/error.cc
@@ -36,6 +36,7 @@
 #include "trigger.h"
 #include "vclock/vclock.h"
 #include "schema.h"
+#include "ssl_error.h"
 
 /* {{{ public API */
 
@@ -213,6 +214,8 @@ ClientError::get_errcode(const struct error *e)
 		return ER_MEMORY_ISSUE;
 	if (type_cast(SystemError, e))
 		return ER_SYSTEM;
+	if (type_cast(SSLError, e))
+		return ER_SSL;
 	if (type_cast(CollationError, e))
 		return ER_CANT_CREATE_COLLATION;
 	if (type_cast(XlogGapError, e))
diff --git a/src/lib/core/ssl_error.cc b/src/lib/core/ssl_error.cc
index 00cdfe9e9e..d7750888e2 100644
--- a/src/lib/core/ssl_error.cc
+++ b/src/lib/core/ssl_error.cc
@@ -5,13 +5,28 @@
  */
 #include "ssl_error.h"
 
+#include <stdarg.h>
 #include <stddef.h>
 
+#include "diag.h"
 #include "reflection.h"
 #include "trivia/config.h"
+#include "trivia/util.h"
 
 #if defined(ENABLE_SSL)
 # error unimplemented
 #endif
 
 const struct type_info type_SSLError = make_type("SSLError", NULL);
+
+struct error *
+BuildSSLError(const char *file, unsigned line, const char *format, ...)
+{
+	void *ptr = xmalloc(sizeof(SSLError));
+	SSLError *err = new(ptr) SSLError(file, line);
+	va_list ap;
+	va_start(ap, format);
+	error_vformat_msg(err, format, ap);
+	va_end(ap);
+	return err;
+}
diff --git a/src/lib/core/ssl_error.h b/src/lib/core/ssl_error.h
index a684cc066e..c6c78df21f 100644
--- a/src/lib/core/ssl_error.h
+++ b/src/lib/core/ssl_error.h
@@ -22,12 +22,18 @@ extern "C" {
 
 extern const struct type_info type_SSLError;
 
+/** Builds an instance of SSLError with the given message. */
+struct error *
+BuildSSLError(const char *file, unsigned line, const char *format, ...);
+
 #if defined(__cplusplus)
 } /* extern "C" */
 
 class SSLError: public Exception {
 public:
-	SSLError(): Exception(&type_SSLError, NULL, 0) {}
+	SSLError(const char *file, unsigned line)
+		: Exception(&type_SSLError, file, line) {}
+	SSLError() : SSLError(NULL, 0) {}
 	virtual void raise() { throw this; }
 };
 
diff --git a/test/box/error.result b/test/box/error.result
index f50f85c181..05244744c7 100644
--- a/test/box/error.result
+++ b/test/box/error.result
@@ -461,6 +461,7 @@ t;
  |   240: box.error.COMPLEX_FOREIGN_KEY_FAILED
  |   241: box.error.WRONG_SPACE_UPGRADE_OPTIONS
  |   242: box.error.NO_ELECTION_QUORUM
+ |   243: box.error.SSL
  | ...
 
 test_run:cmd("setopt delimiter ''");
diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt
index 442597255f..f01557871f 100644
--- a/test/unit/CMakeLists.txt
+++ b/test/unit/CMakeLists.txt
@@ -64,7 +64,7 @@ target_link_libraries(xmalloc.test unit)
 add_executable(datetime.test datetime.c)
 target_link_libraries(datetime.test tzcode core cdt unit)
 add_executable(error.test error.c core_test_utils.c)
-target_link_libraries(error.test unit core)
+target_link_libraries(error.test unit core box_error)
 add_executable(interval.test interval.c core_test_utils.c)
 target_link_libraries(interval.test core unit)
 
diff --git a/test/unit/error.c b/test/unit/error.c
index 55f8f67982..460848df25 100644
--- a/test/unit/error.c
+++ b/test/unit/error.c
@@ -3,11 +3,17 @@
  *
  * Copyright 2010-2021, Tarantool AUTHORS, please see AUTHORS file.
  */
+#include "box/error.h"
+#include "diag.h"
 #include "error_payload.h"
+#include "fiber.h"
+#include "memory.h"
 #include "mp_uuid.h"
 #include "msgpuck.h"
 #include "random.h"
+#include "ssl_error.h"
 #include "unit.h"
+#include "vclock/vclock.h"
 
 #include <float.h>
 
@@ -441,13 +447,47 @@ test_payload_move(void)
 	footer();
 }
 
+static void
+test_error_code(void)
+{
+	header();
+	plan(9);
+
+	diag_set(ClientError, ER_READONLY);
+	is(box_error_code(box_error_last()), ER_READONLY, "ClientError");
+	diag_set(OutOfMemory, 42, "foo", "bar");
+	is(box_error_code(box_error_last()), ER_MEMORY_ISSUE, "OutOfMemory");
+	diag_set(SystemError, "foo");
+	is(box_error_code(box_error_last()), ER_SYSTEM, "SystemError");
+	diag_set(SocketError, "foo", "bar");
+	is(box_error_code(box_error_last()), ER_SYSTEM, "SocketError");
+	diag_set(TimedOut);
+	is(box_error_code(box_error_last()), ER_SYSTEM, "TimedOut");
+	diag_set(SSLError, "foo");
+	is(box_error_code(box_error_last()), ER_SSL, "SSLError");
+	diag_set(CollationError, "foo");
+	is(box_error_code(box_error_last()), ER_CANT_CREATE_COLLATION,
+	   "CollationError");
+	struct vclock vclock;
+	vclock_create(&vclock);
+	diag_set(XlogGapError, &vclock, &vclock);
+	is(box_error_code(box_error_last()), ER_XLOG_GAP, "XlogGapError");
+	diag_set(FiberIsCancelled);
+	is(box_error_code(box_error_last()), ER_PROC_LUA, "FiberIsCancelled");
+
+	check_plan();
+	footer();
+}
+
 int
 main(void)
 {
 	header();
-	plan(9);
+	plan(10);
 
 	random_init();
+	memory_init();
+	fiber_init(fiber_c_invoke);
 
 	test_payload_field_str();
 	test_payload_field_uint();
@@ -458,7 +498,10 @@ main(void)
 	test_payload_field_mp();
 	test_payload_clear();
 	test_payload_move();
+	test_error_code();
 
+	fiber_free();
+	memory_free();
 	random_free();
 
 	footer();
diff --git a/test/unit/error.result b/test/unit/error.result
index daf4e6eb06..4e388c764a 100644
--- a/test/unit/error.result
+++ b/test/unit/error.result
@@ -1,5 +1,5 @@
 	*** main ***
-1..9
+1..10
 	*** test_payload_field_str ***
     1..15
     ok 1 - no fields in the beginning
@@ -158,4 +158,17 @@ ok 8 - subtests
     ok 7 - key
 ok 9 - subtests
 	*** test_payload_move: done ***
+	*** test_error_code ***
+    1..9
+    ok 1 - ClientError
+    ok 2 - OutOfMemory
+    ok 3 - SystemError
+    ok 4 - SocketError
+    ok 5 - TimedOut
+    ok 6 - SSLError
+    ok 7 - CollationError
+    ok 8 - XlogGapError
+    ok 9 - FiberIsCancelled
+ok 10 - subtests
+	*** test_error_code: done ***
 	*** main: done ***
-- 
GitLab