Merge pull request #1344 from dgarske/portability_cleanups

Portability cleanups and `tls_bench` fixes
This commit is contained in:
toddouska
2018-02-09 13:15:47 -08:00
committed by GitHub
10 changed files with 133 additions and 36 deletions

2
.gitignore vendored
View File

@ -57,7 +57,7 @@ ctaocrypt/benchmark/benchmark
ctaocrypt/test/testctaocrypt ctaocrypt/test/testctaocrypt
wolfcrypt/benchmark/benchmark wolfcrypt/benchmark/benchmark
wolfcrypt/test/testwolfcrypt wolfcrypt/test/testwolfcrypt
examples/benchmark/tls-bench examples/benchmark/tls_bench
examples/client/client examples/client/client
examples/echoclient/echoclient examples/echoclient/echoclient
examples/echoserver/echoserver examples/echoserver/echoserver

View File

@ -7,7 +7,7 @@
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
A47546261FD90492005176B9 /* tls-bench.c in Sources */ = {isa = PBXBuildFile; fileRef = A47546251FD90492005176B9 /* tls-bench.c */; }; A47546261FD90492005176B9 /* tls_bench.c in Sources */ = {isa = PBXBuildFile; fileRef = A47546251FD90492005176B9 /* tls_bench.c */; };
A4ADF82F1FCE0BD300A06E90 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = A4ADF82E1FCE0BD300A06E90 /* AppDelegate.m */; }; A4ADF82F1FCE0BD300A06E90 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = A4ADF82E1FCE0BD300A06E90 /* AppDelegate.m */; };
A4ADF8321FCE0BD300A06E90 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A4ADF8311FCE0BD300A06E90 /* ViewController.m */; }; A4ADF8321FCE0BD300A06E90 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A4ADF8311FCE0BD300A06E90 /* ViewController.m */; };
A4ADF8351FCE0BD300A06E90 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A4ADF8331FCE0BD300A06E90 /* Main.storyboard */; }; A4ADF8351FCE0BD300A06E90 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A4ADF8331FCE0BD300A06E90 /* Main.storyboard */; };
@ -87,7 +87,7 @@
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
A47546241FD9042D005176B9 /* user_settings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = user_settings.h; path = ../user_settings.h; sourceTree = "<group>"; }; A47546241FD9042D005176B9 /* user_settings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = user_settings.h; path = ../user_settings.h; sourceTree = "<group>"; };
A47546251FD90492005176B9 /* tls-bench.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "tls-bench.c"; path = "../../../examples/benchmark/tls-bench.c"; sourceTree = "<group>"; }; A47546251FD90492005176B9 /* tls_bench.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tls_bench.c; path = ../../../examples/benchmark/tls_bench.c; sourceTree = "<group>"; };
A4ADF82A1FCE0BD300A06E90 /* wolfBench.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = wolfBench.app; sourceTree = BUILT_PRODUCTS_DIR; }; A4ADF82A1FCE0BD300A06E90 /* wolfBench.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = wolfBench.app; sourceTree = BUILT_PRODUCTS_DIR; };
A4ADF82D1FCE0BD300A06E90 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; }; A4ADF82D1FCE0BD300A06E90 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
A4ADF82E1FCE0BD300A06E90 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; }; A4ADF82E1FCE0BD300A06E90 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
@ -183,7 +183,7 @@
A4ADF8211FCE0BD300A06E90 = { A4ADF8211FCE0BD300A06E90 = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
A47546251FD90492005176B9 /* tls-bench.c */, A47546251FD90492005176B9 /* tls_bench.c */,
A47546241FD9042D005176B9 /* user_settings.h */, A47546241FD9042D005176B9 /* user_settings.h */,
A4ADF85F1FCE0BE300A06E90 /* wolfSSL */, A4ADF85F1FCE0BE300A06E90 /* wolfSSL */,
A4ADF82C1FCE0BD300A06E90 /* wolfBench */, A4ADF82C1FCE0BD300A06E90 /* wolfBench */,
@ -450,7 +450,7 @@
A4ADF86C1FCE0C1C00A06E90 /* internal.c in Sources */, A4ADF86C1FCE0C1C00A06E90 /* internal.c in Sources */,
A4ADF9011FCE0C5600A06E90 /* md2.c in Sources */, A4ADF9011FCE0C5600A06E90 /* md2.c in Sources */,
A4ADF8D61FCE0C5600A06E90 /* sha3.c in Sources */, A4ADF8D61FCE0C5600A06E90 /* sha3.c in Sources */,
A47546261FD90492005176B9 /* tls-bench.c in Sources */, A47546261FD90492005176B9 /* tls_bench.c in Sources */,
A4ADF9161FCE0C5600A06E90 /* fe_operations.c in Sources */, A4ADF9161FCE0C5600A06E90 /* fe_operations.c in Sources */,
A4ADF9001FCE0C5600A06E90 /* poly1305.c in Sources */, A4ADF9001FCE0C5600A06E90 /* poly1305.c in Sources */,
A4ADF8F81FCE0C5600A06E90 /* fe_low_mem.c in Sources */, A4ADF8F81FCE0C5600A06E90 /* fe_low_mem.c in Sources */,

View File

@ -3140,6 +3140,7 @@ AS_IF([test "x$ENABLED_CRYPTONLY" = "xyes"], [ENABLED_EXAMPLES="no"])
AM_CONDITIONAL([BUILD_EXAMPLE_SERVERS], [test "x$ENABLED_EXAMPLES" = "xyes" && test "x$ENABLED_LEANTLS" = "xno"]) AM_CONDITIONAL([BUILD_EXAMPLE_SERVERS], [test "x$ENABLED_EXAMPLES" = "xyes" && test "x$ENABLED_LEANTLS" = "xno"])
AM_CONDITIONAL([BUILD_EXAMPLE_CLIENTS], [test "x$ENABLED_EXAMPLES" = "xyes"]) AM_CONDITIONAL([BUILD_EXAMPLE_CLIENTS], [test "x$ENABLED_EXAMPLES" = "xyes"])
AM_CONDITIONAL([BUILD_TESTS], [test "x$ENABLED_EXAMPLES" = "xyes" && test "x$ENABLED_LEANTLS" = "xno"]) AM_CONDITIONAL([BUILD_TESTS], [test "x$ENABLED_EXAMPLES" = "xyes" && test "x$ENABLED_LEANTLS" = "xno"])
AM_CONDITIONAL([BUILD_THREADED_EXAMPLES], [test "x$ENABLED_SINGLETHREADED" = "xno" && test "x$ENABLED_EXAMPLES" = "xyes" && test "x$ENABLED_LEANTLS" = "xno"])
# Enable wolfCrypt test and benchmark # Enable wolfCrypt test and benchmark
AC_ARG_ENABLE([crypttests], AC_ARG_ENABLE([crypttests],

View File

@ -1,4 +1,15 @@
# vim:ft=automake # vim:ft=automake
# included from Top Level Makefile.am
# All paths should be given relative to the root # All paths should be given relative to the root
EXTRA_DIST+= examples/benchmark/tls-bench.c
if BUILD_THREADED_EXAMPLES
noinst_PROGRAMS += examples/benchmark/tls_bench
noinst_HEADERS += examples/benchmark/tls_bench.h
examples_benchmark_tls_bench_SOURCES = examples/benchmark/tls_bench.c
examples_benchmark_tls_bench_LDADD = src/libwolfssl.la $(LIB_STATIC_ADD)
examples_benchmark_tls_bench_DEPENDENCIES = src/libwolfssl.la
endif
dist_example_DATA+= examples/benchmark/tls_bench.c
DISTCLEANFILES+= examples/benchmark/.libs/tls_bench

View File

@ -1,4 +1,4 @@
/* tls-bench.c /* tls_bench.c
* *
* Copyright (C) 2006-2017 wolfSSL Inc. * Copyright (C) 2006-2017 wolfSSL Inc.
* *
@ -22,22 +22,27 @@
/* /*
Example gcc build statement Example gcc build statement
gcc -lwolfssl -lpthread -o tls-bench tls-bench.c gcc -lwolfssl -lpthread -o tls_bench tls_bench.c
./tls-bench ./tls_bench
Or Or
extern int bench_tls(void); #include <examples/benchmark/tls_bench.h>
bench_tls(); bench_tls();
*/ */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifndef WOLFSSL_USER_SETTINGS #ifndef WOLFSSL_USER_SETTINGS
#include <wolfssl/options.h> #include <wolfssl/options.h>
#endif #endif
#include <wolfssl/wolfcrypt/settings.h> #include <wolfssl/wolfcrypt/settings.h>
#include <wolfssl/ssl.h> #include <wolfssl/ssl.h>
#include <examples/benchmark/tls_bench.h>
/* force certificate test buffers to be included via headers */ /* force certificate test buffers to be included via headers */
#undef USE_CERT_BUFFERS_2048 #undef USE_CERT_BUFFERS_2048
#define USE_CERT_BUFFERS_2048 #define USE_CERT_BUFFERS_2048
@ -257,6 +262,8 @@ static int ServerSend(WOLFSSL* ssl, char* buf, int sz, void* ctx)
pthread_cond_signal(&info->to_client.cond); pthread_cond_signal(&info->to_client.cond);
pthread_mutex_unlock(&info->to_client.mutex); pthread_mutex_unlock(&info->to_client.mutex);
(void)ssl;
return sz; return sz;
} }
@ -286,6 +293,8 @@ static int ServerRecv(WOLFSSL* ssl, char* buf, int sz, void* ctx)
if (info->to_client.done != 0) if (info->to_client.done != 0)
return -1; return -1;
(void)ssl;
return sz; return sz;
} }
@ -310,6 +319,8 @@ static int ClientSend(WOLFSSL* ssl, char* buf, int sz, void* ctx)
pthread_cond_signal(&info->to_server.cond); pthread_cond_signal(&info->to_server.cond);
pthread_mutex_unlock(&info->to_server.mutex); pthread_mutex_unlock(&info->to_server.mutex);
(void)ssl;
return sz; return sz;
} }
@ -336,11 +347,13 @@ static int ClientRecv(WOLFSSL* ssl, char* buf, int sz, void* ctx)
pthread_mutex_unlock(&info->to_client.mutex); pthread_mutex_unlock(&info->to_client.mutex);
(void)ssl;
return sz; return sz;
} }
static void err_sys(const char* msg) static WC_NORETURN void err_sys(const char* msg)
{ {
printf("wolfSSL error: %s\n", msg); printf("wolfSSL error: %s\n", msg);
exit(1); exit(1);
@ -371,18 +384,25 @@ static void* client_thread(void* args)
cli_ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method()); cli_ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method());
if (cli_ctx == NULL) err_sys("error creating ctx"); if (cli_ctx == NULL) err_sys("error creating ctx");
if (strstr(info->cipher, "ECDSA")) #ifndef NO_CERTS
#ifdef HAVE_ECC
if (strstr(info->cipher, "ECDSA")) {
ret = wolfSSL_CTX_load_verify_buffer(cli_ctx, ca_ecc_cert_der_256, sizeof_ca_ecc_cert_der_256, WOLFSSL_FILETYPE_ASN1); ret = wolfSSL_CTX_load_verify_buffer(cli_ctx, ca_ecc_cert_der_256, sizeof_ca_ecc_cert_der_256, WOLFSSL_FILETYPE_ASN1);
}
else else
#endif
{
ret = wolfSSL_CTX_load_verify_buffer(cli_ctx, ca_cert_der_2048, sizeof_ca_cert_der_2048, WOLFSSL_FILETYPE_ASN1); ret = wolfSSL_CTX_load_verify_buffer(cli_ctx, ca_cert_der_2048, sizeof_ca_cert_der_2048, WOLFSSL_FILETYPE_ASN1);
if (ret != SSL_SUCCESS) err_sys("error loading CA"); }
if (ret != WOLFSSL_SUCCESS) err_sys("error loading CA");
#endif
wolfSSL_SetIOSend(cli_ctx, ClientSend); wolfSSL_SetIOSend(cli_ctx, ClientSend);
wolfSSL_SetIORecv(cli_ctx, ClientRecv); wolfSSL_SetIORecv(cli_ctx, ClientRecv);
/* set cipher suite */ /* set cipher suite */
ret = wolfSSL_CTX_set_cipher_list(cli_ctx, info->cipher); ret = wolfSSL_CTX_set_cipher_list(cli_ctx, info->cipher);
if (ret != SSL_SUCCESS) err_sys("error setting cipher suite"); if (ret != WOLFSSL_SUCCESS) err_sys("error setting cipher suite");
#ifndef NO_DH #ifndef NO_DH
wolfSSL_CTX_SetMinDhKey_Sz(cli_ctx, MIN_DHKEY_BITS); wolfSSL_CTX_SetMinDhKey_Sz(cli_ctx, MIN_DHKEY_BITS);
@ -399,7 +419,7 @@ static void* client_thread(void* args)
start = gettime_secs(1); start = gettime_secs(1);
ret = wolfSSL_connect(cli_ssl); ret = wolfSSL_connect(cli_ssl);
start = gettime_secs(0) - start; start = gettime_secs(0) - start;
if (ret != SSL_SUCCESS) { if (ret != WOLFSSL_SUCCESS) {
if (info->shutdown) if (info->shutdown)
break; break;
err_sys("error connecting client"); err_sys("error connecting client");
@ -463,24 +483,36 @@ static void* server_thread(void* args)
srv_ctx = wolfSSL_CTX_new(wolfTLSv1_2_server_method()); srv_ctx = wolfSSL_CTX_new(wolfTLSv1_2_server_method());
if (srv_ctx == NULL) err_sys("error creating server ctx"); if (srv_ctx == NULL) err_sys("error creating server ctx");
if (strstr(info->cipher, "ECDSA")) #ifndef NO_CERTS
#ifdef HAVE_ECC
if (strstr(info->cipher, "ECDSA")) {
ret = wolfSSL_CTX_use_PrivateKey_buffer(srv_ctx, ecc_key_der_256, sizeof_ecc_key_der_256, WOLFSSL_FILETYPE_ASN1); ret = wolfSSL_CTX_use_PrivateKey_buffer(srv_ctx, ecc_key_der_256, sizeof_ecc_key_der_256, WOLFSSL_FILETYPE_ASN1);
}
else else
#endif
{
ret = wolfSSL_CTX_use_PrivateKey_buffer(srv_ctx, server_key_der_2048, sizeof_server_key_der_2048, WOLFSSL_FILETYPE_ASN1); ret = wolfSSL_CTX_use_PrivateKey_buffer(srv_ctx, server_key_der_2048, sizeof_server_key_der_2048, WOLFSSL_FILETYPE_ASN1);
if (ret != SSL_SUCCESS) err_sys("error loading server key"); }
if (ret != WOLFSSL_SUCCESS) err_sys("error loading server key");
if (strstr(info->cipher, "ECDSA")) #ifdef HAVE_ECC
if (strstr(info->cipher, "ECDSA")) {
ret = wolfSSL_CTX_use_certificate_buffer(srv_ctx, serv_ecc_der_256, sizeof_serv_ecc_der_256, WOLFSSL_FILETYPE_ASN1); ret = wolfSSL_CTX_use_certificate_buffer(srv_ctx, serv_ecc_der_256, sizeof_serv_ecc_der_256, WOLFSSL_FILETYPE_ASN1);
}
else else
#endif
{
ret = wolfSSL_CTX_use_certificate_buffer(srv_ctx, server_cert_der_2048, sizeof_server_cert_der_2048, WOLFSSL_FILETYPE_ASN1); ret = wolfSSL_CTX_use_certificate_buffer(srv_ctx, server_cert_der_2048, sizeof_server_cert_der_2048, WOLFSSL_FILETYPE_ASN1);
if (ret != SSL_SUCCESS) err_sys("error loading server cert"); }
if (ret != WOLFSSL_SUCCESS) err_sys("error loading server cert");
#endif
wolfSSL_SetIOSend(srv_ctx, ServerSend); wolfSSL_SetIOSend(srv_ctx, ServerSend);
wolfSSL_SetIORecv(srv_ctx, ServerRecv); wolfSSL_SetIORecv(srv_ctx, ServerRecv);
/* set cipher suite */ /* set cipher suite */
ret = wolfSSL_CTX_set_cipher_list(srv_ctx, info->cipher); ret = wolfSSL_CTX_set_cipher_list(srv_ctx, info->cipher);
if (ret != SSL_SUCCESS) err_sys("error setting cipher suite"); if (ret != WOLFSSL_SUCCESS) err_sys("error setting cipher suite");
#ifndef NO_DH #ifndef NO_DH
wolfSSL_CTX_SetMinDhKey_Sz(srv_ctx, MIN_DHKEY_BITS); wolfSSL_CTX_SetMinDhKey_Sz(srv_ctx, MIN_DHKEY_BITS);
@ -498,7 +530,7 @@ static void* server_thread(void* args)
start = gettime_secs(1); start = gettime_secs(1);
ret = wolfSSL_accept(srv_ssl); ret = wolfSSL_accept(srv_ssl);
start = gettime_secs(0) - start; start = gettime_secs(0) - start;
if (ret != SSL_SUCCESS) { if (ret != WOLFSSL_SUCCESS) {
if (info->shutdown) if (info->shutdown)
break; break;
err_sys("error on server accept"); err_sys("error on server accept");
@ -538,9 +570,14 @@ static void* server_thread(void* args)
return NULL; return NULL;
} }
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
#endif
static void print_stats(stats_t* stat, const char* desc, const char* cipher, int verbose) static void print_stats(stats_t* stat, const char* desc, const char* cipher, int verbose)
{ {
const char* formatStr; const char* formatStr;
if (verbose) { if (verbose) {
formatStr = "wolfSSL %s Benchmark on %s:\n" formatStr = "wolfSSL %s Benchmark on %s:\n"
"\tTotal : %9d bytes\n" "\tTotal : %9d bytes\n"
@ -568,6 +605,9 @@ static void print_stats(stats_t* stat, const char* desc, const char* cipher, int
stat->connTime * 1000, stat->connTime * 1000,
stat->connTime * 1000 / stat->connCount); stat->connTime * 1000 / stat->connCount);
} }
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
int bench_tls(void) int bench_tls(void)
{ {

View File

@ -0,0 +1,30 @@
/* tls_bench.h
*
* Copyright (C) 2006-2017 wolfSSL Inc.
*
* This file is part of wolfSSL.
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
#ifndef WOLFSSL_TLS_BENCH_H
#define WOLFSSL_TLS_BENCH_H
int bench_tls(void);
#endif /* WOLFSSL_TLS_BENCH_H */

View File

@ -101,6 +101,9 @@ STATIC INLINE word32 ByteReverseWord32(word32 value)
return (word32)__REV(value); return (word32)__REV(value);
#elif defined(KEIL_INTRINSICS) #elif defined(KEIL_INTRINSICS)
return (word32)__rev(value); return (word32)__rev(value);
#elif defined(WOLF_ALLOW_BUILTIN) && \
defined(__GNUC_PREREQ) && __GNUC_PREREQ(4, 3)
return (word32)__builtin_bswap32(value);
#elif defined(FAST_ROTATE) #elif defined(FAST_ROTATE)
/* 5 instructions with rotate instruction, 9 without */ /* 5 instructions with rotate instruction, 9 without */
return (rotrFixed(value, 8U) & 0xff00ff00) | return (rotrFixed(value, 8U) & 0xff00ff00) |
@ -141,7 +144,9 @@ STATIC INLINE word64 rotrFixed64(word64 x, word64 y)
STATIC INLINE word64 ByteReverseWord64(word64 value) STATIC INLINE word64 ByteReverseWord64(word64 value)
{ {
#if defined(WOLFCRYPT_SLOW_WORD64) #if defined(WOLF_ALLOW_BUILTIN) && defined(__GNUC_PREREQ) && __GNUC_PREREQ(4, 3)
return (word64)__builtin_bswap64(value);
#elif defined(WOLFCRYPT_SLOW_WORD64)
return (word64)((word64)ByteReverseWord32((word32) value)) << 32 | return (word64)((word64)ByteReverseWord32((word32) value)) << 32 |
(word64)ByteReverseWord32((word32)(value >> 32)); (word64)ByteReverseWord32((word32)(value >> 32));
#else #else

View File

@ -1324,13 +1324,6 @@ enum states {
HANDSHAKE_DONE HANDSHAKE_DONE
}; };
#if defined(__GNUC__)
#define WOLFSSL_PACK __attribute__ ((packed))
#else
#define WOLFSSL_PACK
#endif
/* SSL Version */ /* SSL Version */
typedef struct ProtocolVersion { typedef struct ProtocolVersion {
byte major; byte major;

View File

@ -372,12 +372,6 @@ void join_thread(THREAD_TYPE);
static const word16 wolfSSLPort = 11111; static const word16 wolfSSLPort = 11111;
#if defined(__GNUC__)
#define WC_NORETURN __attribute__((noreturn))
#else
#define WC_NORETURN
#endif
static INLINE WC_NORETURN void err_sys(const char* msg) static INLINE WC_NORETURN void err_sys(const char* msg)
{ {
printf("wolfSSL error: %s\n", msg); printf("wolfSSL error: %s\n", msg);

23
wolfssl/wolfcrypt/types.h Normal file → Executable file
View File

@ -604,6 +604,29 @@
#define EXIT_TEST(ret) return ret #define EXIT_TEST(ret) return ret
#endif #endif
#if defined(__GNUC__)
#define WOLFSSL_PACK __attribute__ ((packed))
#else
#define WOLFSSL_PACK
#endif
#ifndef __GNUC_PREREQ
#if defined(__GNUC__) && defined(__GNUC_MINOR__)
#define __GNUC_PREREQ(maj, min) \
((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
#else
#define __GNUC_PREREQ(maj, min) (0) /* not GNUC */
#endif
#endif
#if defined(__GNUC__)
#define WC_NORETURN __attribute__((noreturn))
#else
#define WC_NORETURN
#endif
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */
#endif #endif